Merge "Changed target path for transaction writing."
diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp
index d936dbe..606477f 100644
--- a/cmds/servicemanager/Access.cpp
+++ b/cmds/servicemanager/Access.cpp
@@ -61,15 +61,21 @@
return gSehandle;
}
+struct AuditCallbackData {
+ const Access::CallingContext* context;
+ const std::string* tname;
+};
+
static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t len) {
- const Access::CallingContext* ad = reinterpret_cast<Access::CallingContext*>(data);
+ const AuditCallbackData* ad = reinterpret_cast<AuditCallbackData*>(data);
if (!ad) {
LOG(ERROR) << "No service manager audit data";
return 0;
}
- snprintf(buf, len, "pid=%d uid=%d", ad->debugPid, ad->uid);
+ snprintf(buf, len, "pid=%d uid=%d name=%s", ad->context->debugPid, ad->context->uid,
+ ad->tname->c_str());
return 0;
}
@@ -113,13 +119,20 @@
}
bool Access::canList(const CallingContext& ctx) {
- return actionAllowed(ctx, mThisProcessContext, "list");
+ return actionAllowed(ctx, mThisProcessContext, "list", "service_manager");
}
-bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm) {
+bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
+ const std::string& tname) {
const char* tclass = "service_manager";
- return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast<void*>(const_cast<CallingContext*>((&sctx))));
+ AuditCallbackData data = {
+ .context = &sctx,
+ .tname = &tname,
+ };
+
+ return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm,
+ reinterpret_cast<void*>(&data));
}
bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) {
@@ -129,7 +142,7 @@
return false;
}
- bool allowed = actionAllowed(sctx, tctx, perm);
+ bool allowed = actionAllowed(sctx, tctx, perm, name);
freecon(tctx);
return allowed;
}
diff --git a/cmds/servicemanager/Access.h b/cmds/servicemanager/Access.h
index 05a60d3..77c2cd4 100644
--- a/cmds/servicemanager/Access.h
+++ b/cmds/servicemanager/Access.h
@@ -45,7 +45,8 @@
virtual bool canList(const CallingContext& ctx);
private:
- bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm);
+ bool actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm,
+ const std::string& tname);
bool actionAllowedFromLookup(const CallingContext& sctx, const std::string& name,
const char *perm);
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index c2c71e0..5f7dc25 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -52,7 +52,6 @@
}
}
- // TODO(b/136023468): move this check to be first
if (!mAccess->canFind(ctx, name)) {
// returns ok and null for legacy reasons
*outBinder = nullptr;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index b230943..c6ce576 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -70,6 +70,7 @@
"ProcessInfoService.cpp",
"ProcessState.cpp",
"Static.cpp",
+ "Stability.cpp",
"Status.cpp",
"TextOutput.cpp",
"IpPrefix.cpp",
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index bdf0f8e..268c85e 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -124,6 +124,7 @@
uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
{
data.setDataPosition(0);
+ data.setTransactingBinder(this);
status_t err = NO_ERROR;
switch (code) {
@@ -135,8 +136,10 @@
break;
}
+ // In case this is being transacted on in the same process.
if (reply != nullptr) {
reply->setDataPosition(0);
+ reply->setTransactingBinder(this);
}
return err;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 5ceb218..57440d5 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -216,6 +216,11 @@
status_t status = IPCThreadState::self()->transact(
mHandle, code, data, reply, flags);
if (status == DEAD_OBJECT) mAlive = 0;
+
+ if (reply != nullptr) {
+ reply->setTransactingBinder(this);
+ }
+
return status;
}
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index cfb86f0..7c45c77 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -465,7 +465,7 @@
void IPCThreadState::flushCommands()
{
- if (mProcess->mDriverFD <= 0)
+ if (mProcess->mDriverFD < 0)
return;
talkWithDriver(false);
// The flush could have caused post-write refcount decrements to have
@@ -618,7 +618,7 @@
int IPCThreadState::setupPolling(int* fd)
{
- if (mProcess->mDriverFD <= 0) {
+ if (mProcess->mDriverFD < 0) {
return -EBADF;
}
@@ -924,7 +924,7 @@
status_t IPCThreadState::talkWithDriver(bool doReceive)
{
- if (mProcess->mDriverFD <= 0) {
+ if (mProcess->mDriverFD < 0) {
return -EBADF;
}
@@ -982,7 +982,7 @@
#else
err = INVALID_OPERATION;
#endif
- if (mProcess->mDriverFD <= 0) {
+ if (mProcess->mDriverFD < 0) {
err = -EBADF;
}
IF_LOG_COMMANDS() {
@@ -1301,7 +1301,7 @@
if (self) {
self->flushCommands();
#if defined(__ANDROID__)
- if (self->mProcess->mDriverFD > 0) {
+ if (self->mProcess->mDriverFD >= 0) {
ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
}
#endif
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 6bd97d58..4d15123 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -77,6 +77,9 @@
namespace android {
+// many things compile this into prebuilts on the stack
+static_assert(sizeof(Parcel) == 60 || sizeof(Parcel) == 120);
+
static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER;
static size_t gParcelGlobalAllocSize = 0;
static size_t gParcelGlobalAllocCount = 0;
@@ -164,14 +167,34 @@
ALOGE("Invalid object type 0x%08x", obj.hdr.type);
}
-inline static status_t finish_flatten_binder(
- const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
+status_t Parcel::finishFlattenBinder(
+ const sp<IBinder>& binder, const flat_binder_object& flat)
{
- return out->writeObject(flat, false);
+ status_t status = writeObject(flat, false);
+ if (status != OK) return status;
+
+ return writeInt32(internal::Stability::get(binder.get()));
}
-static status_t flatten_binder(const sp<ProcessState>& /*proc*/,
- const sp<IBinder>& binder, Parcel* out)
+status_t Parcel::finishUnflattenBinder(
+ const sp<IBinder>& binder, sp<IBinder>* out) const
+{
+ int32_t stability;
+ status_t status = readInt32(&stability);
+ if (status != OK) return status;
+
+ if (!internal::Stability::check(stability, mRequiredStability)) {
+ return BAD_TYPE;
+ }
+
+ status = internal::Stability::set(binder.get(), stability);
+ if (status != OK) return status;
+
+ *out = binder;
+ return OK;
+}
+
+status_t Parcel::flattenBinder(const sp<IBinder>& binder)
{
flat_binder_object obj;
@@ -209,30 +232,24 @@
obj.cookie = 0;
}
- return finish_flatten_binder(binder, obj, out);
+ return finishFlattenBinder(binder, obj);
}
-inline static status_t finish_unflatten_binder(
- BpBinder* /*proxy*/, const flat_binder_object& /*flat*/,
- const Parcel& /*in*/)
+status_t Parcel::unflattenBinder(sp<IBinder>* out) const
{
- return NO_ERROR;
-}
-
-static status_t unflatten_binder(const sp<ProcessState>& proc,
- const Parcel& in, sp<IBinder>* out)
-{
- const flat_binder_object* flat = in.readObject(false);
+ const flat_binder_object* flat = readObject(false);
if (flat) {
switch (flat->hdr.type) {
- case BINDER_TYPE_BINDER:
- *out = reinterpret_cast<IBinder*>(flat->cookie);
- return finish_unflatten_binder(nullptr, *flat, in);
- case BINDER_TYPE_HANDLE:
- *out = proc->getStrongProxyForHandle(flat->handle);
- return finish_unflatten_binder(
- static_cast<BpBinder*>(out->get()), *flat, in);
+ case BINDER_TYPE_BINDER: {
+ sp<IBinder> binder = reinterpret_cast<IBinder*>(flat->cookie);
+ return finishUnflattenBinder(binder, out);
+ }
+ case BINDER_TYPE_HANDLE: {
+ sp<IBinder> binder =
+ ProcessState::self()->getStrongProxyForHandle(flat->handle);
+ return finishUnflattenBinder(binder, out);
+ }
}
}
return BAD_TYPE;
@@ -337,6 +354,10 @@
return NO_ERROR;
}
+void Parcel::setTransactingBinder(const sp<IBinder>& binder) const {
+ mRequiredStability = internal::Stability::get(binder.get());
+}
+
status_t Parcel::setData(const uint8_t* buffer, size_t len)
{
if (len > INT32_MAX) {
@@ -1032,7 +1053,7 @@
status_t Parcel::writeStrongBinder(const sp<IBinder>& val)
{
- return flatten_binder(ProcessState::self(), val, this);
+ return flattenBinder(val);
}
status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
@@ -1978,7 +1999,7 @@
status_t Parcel::readNullableStrongBinder(sp<IBinder>* val) const
{
- return unflatten_binder(ProcessState::self(), *this, val);
+ return unflattenBinder(val);
}
sp<IBinder> Parcel::readStrongBinder() const
@@ -2682,9 +2703,10 @@
mObjectsCapacity = 0;
mNextObjectHint = 0;
mObjectsSorted = false;
+ mAllowFds = true;
mHasFds = false;
mFdsKnown = true;
- mAllowFds = true;
+ mRequiredStability = internal::Stability::UNDECLARED;
mOwner = nullptr;
mOpenAshmemSize = 0;
mWorkSourceRequestHeaderPosition = 0;
diff --git a/libs/binder/Stability.cpp b/libs/binder/Stability.cpp
new file mode 100644
index 0000000..d6d312a
--- /dev/null
+++ b/libs/binder/Stability.cpp
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Stability.h>
+
+namespace android {
+namespace internal {
+
+void Stability::markCompilationUnit(IBinder* binder) {
+#ifdef __ANDROID_VNDK__
+constexpr Stability::Level kLocalStability = Stability::Level::VENDOR;
+#else
+constexpr Stability::Level kLocalStability = Stability::Level::SYSTEM;
+#endif
+
+ status_t result = set(binder, kLocalStability);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+void Stability::markVintf(IBinder* binder) {
+ status_t result = set(binder, Level::VINTF);
+ LOG_ALWAYS_FATAL_IF(result != OK, "Should only mark known object.");
+}
+
+status_t Stability::set(IBinder* binder, int32_t stability) {
+ Level currentStability = get(binder);
+
+ // null binder is always written w/ 'UNDECLARED' stability
+ if (binder == nullptr) {
+ if (stability == UNDECLARED) {
+ return OK;
+ } else {
+ ALOGE("Null binder written with stability %s.", stabilityString(stability).c_str());
+ return BAD_TYPE;
+ }
+ }
+
+ if (!isDeclaredStability(stability)) {
+ // There are UNDECLARED sets because some binder interfaces don't set their stability, and
+ // then UNDECLARED stability is sent on the other side.
+ if (stability != UNDECLARED) {
+ ALOGE("Can only set known stability, not %d.", stability);
+ return BAD_TYPE;
+ }
+ }
+
+ if (currentStability != Level::UNDECLARED && currentStability != stability) {
+ ALOGE("Interface being set with %s but it is already marked as %s.",
+ stabilityString(stability).c_str(), stabilityString(stability).c_str());
+ return BAD_TYPE;
+ }
+
+ if (currentStability == stability) return OK;
+
+ binder->attachObject(
+ reinterpret_cast<void*>(&Stability::get),
+ reinterpret_cast<void*>(stability),
+ nullptr /*cleanupCookie*/,
+ nullptr /*cleanup function*/);
+
+ return OK;
+}
+
+Stability::Level Stability::get(IBinder* binder) {
+ if (binder == nullptr) return UNDECLARED;
+
+ return static_cast<Level>(reinterpret_cast<intptr_t>(
+ binder->findObject(reinterpret_cast<void*>(&Stability::get))));
+}
+
+bool Stability::check(int32_t provided, Level required) {
+ bool stable = (provided & required) == required;
+
+ if (!isDeclaredStability(provided) && provided != UNDECLARED) {
+ ALOGE("Unknown stability when checking interface stability %d.", provided);
+
+ stable = false;
+ }
+
+ if (!stable) {
+ ALOGE("Interface with %s cannot accept interface with %s.",
+ stabilityString(required).c_str(),
+ stabilityString(provided).c_str());
+ }
+
+ return stable;
+}
+
+bool Stability::isDeclaredStability(int32_t stability) {
+ return stability == VENDOR || stability == SYSTEM || stability == VINTF;
+}
+
+std::string Stability::stabilityString(int32_t stability) {
+ switch (stability) {
+ case Level::UNDECLARED: return "undeclared stability";
+ case Level::VENDOR: return "vendor stability";
+ case Level::SYSTEM: return "system stability";
+ case Level::VINTF: return "vintf stability";
+ }
+ return "unknown stability " + std::to_string(stability);
+}
+
+} // namespace internal
+} // namespace stability
\ No newline at end of file
diff --git a/libs/binder/TEST_MAPPING b/libs/binder/TEST_MAPPING
index 01e57d3..136bdb0 100644
--- a/libs/binder/TEST_MAPPING
+++ b/libs/binder/TEST_MAPPING
@@ -11,6 +11,9 @@
},
{
"name": "binderLibTest"
+ },
+ {
+ "name": "binderStabilityTest"
}
]
}
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index cf3ef84..1537e69 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -54,9 +54,9 @@
virtual void attachObject( const void* objectID,
void* object,
void* cleanupCookie,
- object_cleanup_func func);
- virtual void* findObject(const void* objectID) const;
- virtual void detachObject(const void* objectID);
+ object_cleanup_func func) final;
+ virtual void* findObject(const void* objectID) const final;
+ virtual void detachObject(const void* objectID) final;
virtual BBinder* localBinder();
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index b3a1d0b..e71541b 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -61,9 +61,9 @@
virtual void attachObject( const void* objectID,
void* object,
void* cleanupCookie,
- object_cleanup_func func);
- virtual void* findObject(const void* objectID) const;
- virtual void detachObject(const void* objectID);
+ object_cleanup_func func) final;
+ virtual void* findObject(const void* objectID) const final;
+ virtual void detachObject(const void* objectID) final;
virtual BpBinder* remoteBinder();
diff --git a/libs/binder/include/binder/Parcel.h b/libs/binder/include/binder/Parcel.h
index 28ab4d9..698fc07 100644
--- a/libs/binder/include/binder/Parcel.h
+++ b/libs/binder/include/binder/Parcel.h
@@ -33,6 +33,7 @@
#include <binder/IInterface.h>
#include <binder/Parcelable.h>
+#include <binder/Stability.h>
// ---------------------------------------------------------------------------
namespace android {
@@ -67,7 +68,9 @@
status_t setDataSize(size_t size);
void setDataPosition(size_t pos) const;
status_t setDataCapacity(size_t size);
-
+
+ void setTransactingBinder(const sp<IBinder>& binder) const;
+
status_t setData(const uint8_t* buffer, size_t len);
status_t appendFrom(const Parcel *parcel,
@@ -419,7 +422,13 @@
void scanForFds() const;
status_t validateReadData(size_t len) const;
void updateWorkSourceRequestHeaderPosition() const;
-
+
+ status_t finishFlattenBinder(const sp<IBinder>& binder,
+ const flat_binder_object& flat);
+ status_t finishUnflattenBinder(const sp<IBinder>& binder, sp<IBinder>* out) const;
+ status_t flattenBinder(const sp<IBinder>& binder);
+ status_t unflattenBinder(sp<IBinder>* out) const;
+
template<class T>
status_t readAligned(T *pArg) const;
@@ -466,13 +475,15 @@
size_t mObjectsCapacity;
mutable size_t mNextObjectHint;
mutable bool mObjectsSorted;
+ bool mAllowFds;
mutable bool mRequestHeaderPresent;
mutable size_t mWorkSourceRequestHeaderPosition;
mutable bool mFdsKnown;
mutable bool mHasFds;
- bool mAllowFds;
+
+ mutable internal::Stability::Level mRequiredStability;
release_func mOwner;
void* mOwnerCookie;
diff --git a/libs/binder/include/binder/Stability.h b/libs/binder/include/binder/Stability.h
new file mode 100644
index 0000000..487f480
--- /dev/null
+++ b/libs/binder/include/binder/Stability.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/IBinder.h>
+#include <string>
+
+namespace android {
+namespace internal {
+
+// WARNING: These APIs are only ever expected to be called by auto-generated code.
+// Instead of calling them, you should set the stability of a .aidl interface
+class Stability final {
+public:
+ // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
+ // change or modify the stability class of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder compilation unit
+ static void markCompilationUnit(IBinder* binder);
+ // WARNING: This is only ever expected to be called by auto-generated code. You likely want to
+ // change or modify the stability class of the interface you are using.
+ // This must be called as soon as the binder in question is constructed. No thread safety
+ // is provided.
+ // E.g. stability is according to libbinder_ndk or Java SDK AND the interface
+ // expressed here is guaranteed to be stable for multiple years (Stable AIDL)
+ static void markVintf(IBinder* binder);
+
+private:
+ // Parcel needs to store stability level since this is more efficient than storing and looking
+ // up the efficiency level of a binder object. So, we expose the underlying type.
+ friend ::android::Parcel;
+
+ enum Level : int16_t {
+ UNDECLARED = 0,
+
+ VENDOR = 0b000011,
+ SYSTEM = 0b001100,
+ VINTF = 0b111111,
+ };
+
+ // applies stability to binder if stability level is known
+ __attribute__((warn_unused_result))
+ static status_t set(IBinder* binder, int32_t stability);
+
+ static Level get(IBinder* binder);
+
+ static bool check(int32_t provided, Level required);
+
+ static bool isDeclaredStability(int32_t stability);
+ static std::string stabilityString(int32_t stability);
+
+ Stability();
+};
+
+} // namespace internal
+} // namespace android
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 44a691d..05db81e 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -137,3 +137,18 @@
],
test_suites: ["device-tests"],
}
+
+cc_test {
+ name: "binderStabilityTest",
+ defaults: ["binder_test_defaults"],
+ srcs: [
+ "binderStabilityTest.cpp",
+ "IBinderStabilityTest.aidl",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "libutils",
+ ],
+ test_suites: ["device-tests"],
+}
diff --git a/libs/binder/tests/IBinderStabilityTest.aidl b/libs/binder/tests/IBinderStabilityTest.aidl
new file mode 100644
index 0000000..7540ec9
--- /dev/null
+++ b/libs/binder/tests/IBinderStabilityTest.aidl
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+// THIS IS ONLY FOR TESTING!
+interface IBinderStabilityTest {
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ void sendBinder(IBinder binder);
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinder returnNoStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinder returnLocalStabilityBinder();
+
+ // DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+ // THIS IS ONLY FOR TESTING!
+ IBinder returnVintfStabilityBinder();
+}
+// DO NOT EVER IN A MILLION YEARS WRITE AN INTERFACE LIKE THIS!
+// THIS IS ONLY FOR TESTING!
+// Construct and return a binder with a specific stability
diff --git a/libs/binder/tests/binderStabilityTest.cpp b/libs/binder/tests/binderStabilityTest.cpp
new file mode 100644
index 0000000..2b27a81
--- /dev/null
+++ b/libs/binder/tests/binderStabilityTest.cpp
@@ -0,0 +1,245 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/os/IServiceManager.h>
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/Stability.h>
+#include <gtest/gtest.h>
+
+#include <sys/prctl.h>
+
+#include "BnBinderStabilityTest.h"
+#include "BpBinderStabilityTest.h"
+
+using namespace android;
+using android::binder::Status;
+using android::os::IServiceManager;
+
+const String16 kNoStabilityServer = String16("binder_stability_test_service_low");
+const String16 kCompilationUnitServer = String16("binder_stability_test_service_compl");
+const String16 kVintfServer = String16("binder_stability_test_service_vintf");
+
+sp<IBinder> getCompilationUnitStability() {
+ sp<IBinder> binder = new BBinder();
+ // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
+ // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
+ internal::Stability::markCompilationUnit(binder.get()); // <- BAD, NO! DO NOT COPY
+ return binder;
+}
+
+sp<IBinder> getVintfStability() {
+ sp<IBinder> binder = new BBinder();
+ // NO! NO! NO! NO! DO NOT EVERY DO SOMETHING LIKE THIS?
+ // WHAT ARE YOU CRAZY? IT'S VERY DANGEROUS
+ internal::Stability::markVintf(binder.get()); // <- BAD, NO! DO NOT COPY
+ return binder;
+}
+
+// NO! NO! NO! Do not even think of doing something like this!
+// This is for testing! If a class like this was actually used in production,
+// it would ruin everything!
+class BadStabilityTester : public BnBinderStabilityTest {
+public:
+ Status sendBinder(const sp<IBinder>& /*binder*/) override {
+ return Status::ok();
+ }
+ Status returnNoStabilityBinder(sp<IBinder>* _aidl_return) override {
+ *_aidl_return = new BBinder();
+ return Status::ok();
+ }
+ Status returnLocalStabilityBinder(sp<IBinder>* _aidl_return) override {
+ *_aidl_return = getCompilationUnitStability();
+ return Status::ok();
+ }
+ Status returnVintfStabilityBinder(sp<IBinder>* _aidl_return) override {
+ *_aidl_return = getVintfStability();
+ return Status::ok();
+ }
+
+ static sp<IBinderStabilityTest> getNoStabilityServer() {
+ sp<IBinder> remote = new BadStabilityTester;
+ return new BpBinderStabilityTest(remote);
+ }
+ static sp<IBinderStabilityTest> getCompilationUnitStabilityServer() {
+ sp<IBinder> remote = new BadStabilityTester;
+ internal::Stability::markCompilationUnit(remote.get());
+ return new BpBinderStabilityTest(remote);
+ }
+ static sp<IBinderStabilityTest> getVintfStabilityServer() {
+ sp<IBinder> remote = new BadStabilityTester;
+ internal::Stability::markVintf(remote.get()); // <- BAD, NO! DO NOT COPY
+ return new BpBinderStabilityTest(remote);
+ }
+};
+
+void checkNoStabilityServer(const sp<IBinderStabilityTest>& unkemptServer) {
+ EXPECT_TRUE(unkemptServer->sendBinder(new BBinder()).isOk());
+ EXPECT_TRUE(unkemptServer->sendBinder(getCompilationUnitStability()).isOk());
+ EXPECT_TRUE(unkemptServer->sendBinder(getVintfStability()).isOk());
+
+ sp<IBinder> out;
+ EXPECT_TRUE(unkemptServer->returnNoStabilityBinder(&out).isOk());
+ EXPECT_NE(nullptr, out.get());
+
+ EXPECT_TRUE(unkemptServer->returnLocalStabilityBinder(&out).isOk());
+ EXPECT_NE(nullptr, out.get());
+
+ EXPECT_TRUE(unkemptServer->returnVintfStabilityBinder(&out).isOk());
+ EXPECT_NE(nullptr, out.get());
+}
+
+void checkLowStabilityServer(const sp<IBinderStabilityTest>& complServer) {
+ EXPECT_FALSE(complServer->sendBinder(new BBinder()).isOk());
+ EXPECT_TRUE(complServer->sendBinder(getCompilationUnitStability()).isOk());
+ EXPECT_TRUE(complServer->sendBinder(getVintfStability()).isOk());
+
+ sp<IBinder> out;
+ EXPECT_FALSE(complServer->returnNoStabilityBinder(&out).isOk());
+ EXPECT_EQ(nullptr, out.get());
+
+ EXPECT_TRUE(complServer->returnLocalStabilityBinder(&out).isOk());
+ EXPECT_NE(nullptr, out.get());
+
+ EXPECT_TRUE(complServer->returnVintfStabilityBinder(&out).isOk());
+ EXPECT_NE(nullptr, out.get());
+}
+
+void checkHighStabilityServer(const sp<IBinderStabilityTest>& highStability) {
+ EXPECT_FALSE(highStability->sendBinder(new BBinder()).isOk());
+ EXPECT_FALSE(highStability->sendBinder(getCompilationUnitStability()).isOk());
+ EXPECT_TRUE(highStability->sendBinder(getVintfStability()).isOk());
+
+ sp<IBinder> out;
+ EXPECT_FALSE(highStability->returnNoStabilityBinder(&out).isOk());
+ EXPECT_EQ(nullptr, out.get());
+
+ EXPECT_FALSE(highStability->returnLocalStabilityBinder(&out).isOk());
+ EXPECT_EQ(nullptr, out.get());
+
+ EXPECT_TRUE(highStability->returnVintfStabilityBinder(&out).isOk());
+ EXPECT_NE(nullptr, out.get());
+}
+
+TEST(BinderStability, LocalNoStabilityServer) {
+ // in practice, a low stability server is probably one that hasn't been rebuilt
+ // or was written by hand.
+ auto server = BadStabilityTester::getNoStabilityServer();
+ ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder());
+ checkNoStabilityServer(server);
+}
+
+TEST(BinderStability, LocalLowStabilityServer) {
+ auto server = BadStabilityTester::getCompilationUnitStabilityServer();
+ ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder());
+ checkLowStabilityServer(server);
+}
+
+TEST(BinderStability, LocalHighStabilityServer) {
+ auto server = BadStabilityTester::getVintfStabilityServer();
+ ASSERT_NE(nullptr, IInterface::asBinder(server)->localBinder());
+ checkHighStabilityServer(server);
+}
+
+TEST(BinderStability, RemoteNoStabilityServer) {
+ sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kNoStabilityServer);
+ auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+ checkNoStabilityServer(remoteServer);
+}
+
+TEST(BinderStability, RemoteLowStabilityServer) {
+ sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kCompilationUnitServer);
+ auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+ checkLowStabilityServer(remoteServer);
+}
+
+TEST(BinderStability, RemoteVintfServer) {
+ sp<IBinder> remoteBinder = android::defaultServiceManager()->getService(kVintfServer);
+ auto remoteServer = interface_cast<IBinderStabilityTest>(remoteBinder);
+
+ ASSERT_NE(nullptr, remoteServer.get());
+ ASSERT_NE(nullptr, IInterface::asBinder(remoteServer)->remoteBinder());
+
+ checkHighStabilityServer(remoteServer);
+}
+
+class MarksStabilityInConstructor : public BBinder {
+public:
+ static bool gDestructed;
+
+ MarksStabilityInConstructor() {
+ internal::Stability::markCompilationUnit(this);
+ }
+ ~MarksStabilityInConstructor() {
+ gDestructed = true;
+ }
+};
+bool MarksStabilityInConstructor::gDestructed = false;
+
+TEST(BinderStability, MarkingObjectNoDestructTest) {
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ // best practice is to put this directly in an sp, but for this test, we
+ // want to explicitly check what happens before that happens
+ MarksStabilityInConstructor* binder = new MarksStabilityInConstructor();
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ sp<MarksStabilityInConstructor> binderSp = binder;
+ ASSERT_FALSE(MarksStabilityInConstructor::gDestructed);
+
+ binderSp = nullptr;
+ ASSERT_TRUE(MarksStabilityInConstructor::gDestructed);
+}
+
+int main(int argc, char** argv) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ if (fork() == 0) {
+ // child process
+ prctl(PR_SET_PDEATHSIG, SIGHUP);
+
+ sp<IBinder> noStability = new BadStabilityTester;
+ android::defaultServiceManager()->addService(kNoStabilityServer, noStability);
+
+ sp<IBinder> compil = new BadStabilityTester;
+ internal::Stability::markCompilationUnit(compil.get());
+ android::defaultServiceManager()->addService(kCompilationUnitServer, compil);
+
+ sp<IBinder> vintf = new BadStabilityTester;
+ internal::Stability::markVintf(vintf.get());
+ android::defaultServiceManager()->addService(kVintfServer, vintf);
+
+ IPCThreadState::self()->joinThreadPool(true);
+ exit(1); // should not reach
+ }
+
+ // This is not racey. Just giving these services some time to register before we call
+ // getService which sleeps for much longer...
+ usleep(10000);
+
+ return RUN_ALL_TESTS();
+}
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 2cc6857..2bbb0ee 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -187,3 +187,11 @@
"tests",
"tools",
]
+
+filegroup {
+ name: "libui_host_common",
+ srcs: [
+ "Rect.cpp",
+ "PixelFormat.cpp"
+ ],
+}
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index fc40eaf..019815c 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -4237,53 +4237,55 @@
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
CommandEntry* commandEntry) {
sp<Connection> connection = commandEntry->connection;
- nsecs_t finishTime = commandEntry->eventTime;
+ const nsecs_t finishTime = commandEntry->eventTime;
uint32_t seq = commandEntry->seq;
- bool handled = commandEntry->handled;
+ const bool handled = commandEntry->handled;
// Handle post-event policy actions.
DispatchEntry* dispatchEntry = connection->findWaitQueueEntry(seq);
- if (dispatchEntry) {
- nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
- if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
- std::string msg =
- StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
- connection->getWindowName().c_str(), eventDuration * 0.000001f);
- dispatchEntry->eventEntry->appendDescription(msg);
- ALOGI("%s", msg.c_str());
- }
-
- bool restartEvent;
- if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
- KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
- restartEvent = afterKeyEventLockedInterruptible(connection,
- dispatchEntry, keyEntry, handled);
- } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
- MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
- restartEvent = afterMotionEventLockedInterruptible(connection,
- dispatchEntry, motionEntry, handled);
- } else {
- restartEvent = false;
- }
-
- // Dequeue the event and start the next cycle.
- // Note that because the lock might have been released, it is possible that the
- // contents of the wait queue to have been drained, so we need to double-check
- // a few things.
- if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
- connection->waitQueue.dequeue(dispatchEntry);
- traceWaitQueueLength(connection);
- if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
- connection->outboundQueue.enqueueAtHead(dispatchEntry);
- traceOutboundQueueLength(connection);
- } else {
- releaseDispatchEntry(dispatchEntry);
- }
- }
-
- // Start the next dispatch cycle for this connection.
- startDispatchCycleLocked(now(), connection);
+ if (!dispatchEntry) {
+ return;
}
+
+ nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
+ if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
+ std::string msg =
+ StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
+ connection->getWindowName().c_str(), eventDuration * 0.000001f);
+ dispatchEntry->eventEntry->appendDescription(msg);
+ ALOGI("%s", msg.c_str());
+ }
+
+ bool restartEvent;
+ if (dispatchEntry->eventEntry->type == EventEntry::TYPE_KEY) {
+ KeyEntry* keyEntry = static_cast<KeyEntry*>(dispatchEntry->eventEntry);
+ restartEvent =
+ afterKeyEventLockedInterruptible(connection, dispatchEntry, keyEntry, handled);
+ } else if (dispatchEntry->eventEntry->type == EventEntry::TYPE_MOTION) {
+ MotionEntry* motionEntry = static_cast<MotionEntry*>(dispatchEntry->eventEntry);
+ restartEvent = afterMotionEventLockedInterruptible(connection, dispatchEntry, motionEntry,
+ handled);
+ } else {
+ restartEvent = false;
+ }
+
+ // Dequeue the event and start the next cycle.
+ // Note that because the lock might have been released, it is possible that the
+ // contents of the wait queue to have been drained, so we need to double-check
+ // a few things.
+ if (dispatchEntry == connection->findWaitQueueEntry(seq)) {
+ connection->waitQueue.dequeue(dispatchEntry);
+ traceWaitQueueLength(connection);
+ if (restartEvent && connection->status == Connection::STATUS_NORMAL) {
+ connection->outboundQueue.enqueueAtHead(dispatchEntry);
+ traceOutboundQueueLength(connection);
+ } else {
+ releaseDispatchEntry(dispatchEntry);
+ }
+ }
+
+ // Start the next dispatch cycle for this connection.
+ startDispatchCycleLocked(now(), connection);
}
bool InputDispatcher::afterKeyEventLockedInterruptible(const sp<Connection>& connection,
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 59ea9af..87bec11 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -132,13 +132,15 @@
return inverse(tr);
}
-bool BufferLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
+std::optional<renderengine::LayerSettings> BufferLayer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
ATRACE_CALL();
- Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
- supportProtectedContent, layer);
+
+ auto result = Layer::prepareClientComposition(targetSettings);
+ if (!result) {
+ return result;
+ }
+
if (CC_UNLIKELY(mActiveBuffer == 0)) {
// the texture has not been created yet, this Layer has
// in fact never been drawn into. This happens frequently with
@@ -159,15 +161,16 @@
under.orSelf(layer->visibleRegion);
});
// if not everything below us is covered, we plug the holes!
- Region holes(clip.subtract(under));
+ Region holes(targetSettings.clip.subtract(under));
if (!holes.isEmpty()) {
- clearRegion.orSelf(holes);
+ targetSettings.clearRegion.orSelf(holes);
}
- return false;
+ return std::nullopt;
}
- bool blackOutLayer =
- (isProtected() && !supportProtectedContent) || (isSecure() && !renderArea.isSecure());
+ bool blackOutLayer = (isProtected() && !targetSettings.supportProtectedContent) ||
+ (isSecure() && !targetSettings.isSecure);
const State& s(getDrawingState());
+ auto& layer = *result;
if (!blackOutLayer) {
layer.source.buffer.buffer = mActiveBuffer;
layer.source.buffer.isOpaque = isOpaque(s);
@@ -176,8 +179,7 @@
layer.source.buffer.usePremultipliedAlpha = getPremultipledAlpha();
layer.source.buffer.isY410BT2020 = isHdrY410();
// TODO: we could be more subtle with isFixedSize()
- const bool useFiltering = needsFiltering(renderArea.getDisplayDevice()) ||
- renderArea.needsFiltering() || isFixedSize();
+ const bool useFiltering = targetSettings.needsFiltering || mNeedsFiltering || isFixedSize();
// Query the texture matrix given our current filtering mode.
float textureMatrix[16];
@@ -244,7 +246,7 @@
layer.alpha = 1.0;
}
- return true;
+ return result;
}
bool BufferLayer::isHdrY410() const {
@@ -572,21 +574,23 @@
}
bool BufferLayer::needsFiltering(const sp<const DisplayDevice>& displayDevice) const {
- // If we are not capturing based on the state of a known display device, we
- // only return mNeedsFiltering
+ // If we are not capturing based on the state of a known display device,
+ // just return false.
if (displayDevice == nullptr) {
- return mNeedsFiltering;
+ return false;
}
const auto outputLayer = findOutputLayerForDisplay(displayDevice);
if (outputLayer == nullptr) {
- return mNeedsFiltering;
+ return false;
}
+ // We need filtering if the sourceCrop rectangle size does not match the
+ // displayframe rectangle size (not a 1:1 render)
const auto& compositionState = outputLayer->getState();
const auto displayFrame = compositionState.displayFrame;
const auto sourceCrop = compositionState.sourceCrop;
- return mNeedsFiltering || sourceCrop.getHeight() != displayFrame.getHeight() ||
+ return sourceCrop.getHeight() != displayFrame.getHeight() ||
sourceCrop.getWidth() != displayFrame.getWidth();
}
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index bb0205d..c86acf0 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -82,7 +82,6 @@
bool isHdrY410() const override;
- bool onPreComposition(nsecs_t refreshStartTime) override;
bool onPostComposition(const std::optional<DisplayId>& displayId,
const std::shared_ptr<FenceTime>& glDoneFence,
const std::shared_ptr<FenceTime>& presentFence,
@@ -146,7 +145,13 @@
virtual status_t updateFrameNumber(nsecs_t latchTime) = 0;
protected:
- void latchPerFrameState(compositionengine::LayerFECompositionState& outState) const override;
+ /*
+ * compositionengine::LayerFE overrides
+ */
+ bool onPreComposition(nsecs_t) override;
+ void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
// Loads the corresponding system property once per process
static bool latchUnsignaledBuffers();
@@ -163,15 +168,9 @@
bool mRefreshPending{false};
- // prepareClientLayer - constructs a RenderEngine layer for GPU composition.
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) override;
-
private:
// Returns true if this layer requires filtering
- bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const;
+ bool needsFiltering(const sp<const DisplayDevice>& displayDevice) const override;
uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index f15957a..b65d351 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -50,16 +50,14 @@
ColorLayer::~ColorLayer() = default;
-bool ColorLayer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- Layer::prepareClientLayer(renderArea, clip, useIdentityTransform, clearRegion,
- supportProtectedContent, layer);
- half4 color(getColor());
- half3 solidColor(color.r, color.g, color.b);
- layer.source.solidColor = solidColor;
- return true;
+std::optional<renderengine::LayerSettings> ColorLayer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ auto result = Layer::prepareClientComposition(targetSettings);
+ if (!result) {
+ return result;
+ }
+ result->source.solidColor = getColor().rgb;
+ return result;
}
bool ColorLayer::isVisible() const {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 2483ff0..015b939 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -39,16 +39,13 @@
void commitTransaction(const State& stateToCommit) override;
- bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
-
protected:
- virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
-
-private:
+ /*
+ * compositionengine::LayerFE overrides
+ */
void latchPerFrameState(compositionengine::LayerFECompositionState&) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
std::shared_ptr<compositionengine::Layer> mCompositionLayer;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
index 1f2cae9..94fab1f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/LayerFE.h
@@ -16,6 +16,9 @@
#pragma once
+#include <optional>
+
+#include <renderengine/LayerSettings.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
@@ -40,6 +43,34 @@
// geometry state can be skipped.
virtual void latchCompositionState(LayerFECompositionState&, bool includeGeometry) const = 0;
+ struct ClientCompositionTargetSettings {
+ // The clip region, or visible region that is being rendered to
+ const Region& clip;
+
+ // If true, the layer should use an identity transform for its position
+ // transform. Used only by the captureScreen API call.
+ const bool useIdentityTransform;
+
+ // If set to true, the layer should enable filtering when rendering.
+ const bool needsFiltering;
+
+ // If set to true, the buffer is being sent to a destination that is
+ // expected to treat the buffer contents as secure.
+ const bool isSecure;
+
+ // If set to true, the target buffer has protected content support.
+ const bool supportProtectedContent;
+
+ // Modified by each call to prepareClientComposition to indicate the
+ // region of the target buffer that should be cleared.
+ Region& clearRegion;
+ };
+
+ // Returns the LayerSettings to pass to RenderEngine::drawLayers, or
+ // nullopt_t if the layer does not render
+ virtual std::optional<renderengine::LayerSettings> prepareClientComposition(
+ ClientCompositionTargetSettings&) = 0;
+
// Called after the layer is displayed to update the presentation fence
virtual void onLayerDisplayed(const sp<Fence>&) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 5b9e282..4dfcfa4 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -19,8 +19,10 @@
#include <cstdint>
#include <optional>
#include <string>
+#include <unordered_map>
#include <math/mat4.h>
+#include <ui/Fence.h>
#include <ui/GraphicTypes.h>
#include <ui/Region.h>
#include <ui/Transform.h>
@@ -28,6 +30,10 @@
#include "DisplayHardware/DisplayIdentification.h"
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
namespace android::compositionengine {
class DisplayColorProfile;
@@ -48,6 +54,12 @@
using OutputLayers = std::vector<std::unique_ptr<compositionengine::OutputLayer>>;
using ReleasedLayers = std::vector<wp<LayerFE>>;
+ struct FrameFences {
+ sp<Fence> presentFence{Fence::NO_FENCE};
+ sp<Fence> clientTargetAcquireFence{Fence::NO_FENCE};
+ std::unordered_map<HWC2::Layer*, sp<Fence>> layerFences;
+ };
+
virtual ~Output();
// Returns true if the output is valid. This is meant to be checked post-
@@ -132,15 +144,26 @@
// Gets the ordered set of output layers for this output
virtual const OutputLayers& getOutputLayersOrderedByZ() const = 0;
- // Sets the new set of layers being released this frame.
+ // Sets the new set of layers being released this frame
virtual void setReleasedLayers(ReleasedLayers&&) = 0;
// Takes (moves) the set of layers being released this frame.
virtual ReleasedLayers takeReleasedLayers() = 0;
+ // Signals that a frame is beginning on the output
+ virtual void beginFrame() = 0;
+
+ // Prepares a frame for display
+ virtual void prepareFrame() = 0;
+
+ // Posts the new frame, and sets release fences.
+ virtual void postFramebuffer() = 0;
+
protected:
virtual void setDisplayColorProfile(std::unique_ptr<DisplayColorProfile>) = 0;
virtual void setRenderSurface(std::unique_ptr<RenderSurface>) = 0;
+ virtual void chooseCompositionStrategy() = 0;
+ virtual FrameFences presentAndGetFrameFences() = 0;
};
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
index d3a4e09..d7f00a9 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/OutputLayer.h
@@ -21,8 +21,13 @@
#include <utils/StrongPointer.h>
+#include "DisplayHardware/ComposerHal.h"
#include "DisplayHardware/DisplayIdentification.h"
+namespace HWC2 {
+class Layer;
+} // namespace HWC2
+
namespace android {
namespace compositionengine {
@@ -73,6 +78,21 @@
// skipped.
virtual void writeStateToHWC(bool includeGeometry) = 0;
+ // Returns the HWC2::Layer associated with this layer, if it exists
+ virtual HWC2::Layer* getHwcLayer() const = 0;
+
+ // Returns true if the current layer state requires client composition
+ virtual bool requiresClientComposition() const = 0;
+
+ // Applies a HWC device requested composition type change
+ virtual void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) = 0;
+
+ // Prepares to apply any HWC device layer requests
+ virtual void prepareForDeviceLayerRequests() = 0;
+
+ // Applies a HWC device layer request
+ virtual void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) = 0;
+
// Debugging
virtual void dump(std::string& result) const = 0;
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
index 9bff73e..6859846 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/RenderSurface.h
@@ -71,7 +71,7 @@
virtual status_t beginFrame(bool mustRecompose) = 0;
// Prepares the frame for rendering
- virtual status_t prepareFrame() = 0;
+ virtual void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) = 0;
// Allocates a buffer as scratch space for GPU composition
virtual sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
index 1265533..795061a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Display.h
@@ -16,12 +16,13 @@
#pragma once
-#include <memory>
-
#include <compositionengine/Display.h>
#include <compositionengine/impl/Output.h>
+#include <memory>
+
#include "DisplayHardware/DisplayIdentification.h"
+#include "DisplayHardware/HWComposer.h"
namespace android::compositionengine {
@@ -40,6 +41,8 @@
void dump(std::string&) const override;
void setColorTransform(const mat4&) override;
void setColorMode(ui::ColorMode, ui::Dataspace, ui::RenderIntent, ui::Dataspace) override;
+ void chooseCompositionStrategy() override;
+ compositionengine::Output::FrameFences presentAndGetFrameFences() override;
// compositionengine::Display overrides
const std::optional<DisplayId>& getId() const override;
@@ -49,12 +52,22 @@
void createDisplayColorProfile(compositionengine::DisplayColorProfileCreationArgs&&) override;
void createRenderSurface(compositionengine::RenderSurfaceCreationArgs&&) override;
+ // Internal helpers used by chooseCompositionStrategy()
+ using ChangedTypes = android::HWComposer::DeviceRequestedChanges::ChangedTypes;
+ using DisplayRequests = android::HWComposer::DeviceRequestedChanges::DisplayRequests;
+ using LayerRequests = android::HWComposer::DeviceRequestedChanges::LayerRequests;
+ virtual bool anyLayersRequireClientComposition() const;
+ virtual bool allLayersRequireClientComposition() const;
+ virtual void applyChangedTypesToLayers(const ChangedTypes&);
+ virtual void applyDisplayRequests(const DisplayRequests&);
+ virtual void applyLayerRequestsToLayers(const LayerRequests&);
+
private:
const bool mIsVirtual;
std::optional<DisplayId> mId;
};
-std::shared_ptr<compositionengine::Display> createDisplay(
- const compositionengine::CompositionEngine&, compositionengine::DisplayCreationArgs&&);
+std::shared_ptr<Display> createDisplay(const compositionengine::CompositionEngine&,
+ compositionengine::DisplayCreationArgs&&);
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 20812d2..5f4a764 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -75,12 +75,18 @@
void setReleasedLayers(ReleasedLayers&&) override;
ReleasedLayers takeReleasedLayers() override;
+ void beginFrame() override;
+ void prepareFrame() override;
+ void postFramebuffer() override;
+
// Testing
void setDisplayColorProfileForTest(std::unique_ptr<compositionengine::DisplayColorProfile>);
void setRenderSurfaceForTest(std::unique_ptr<compositionengine::RenderSurface>);
protected:
const CompositionEngine& getCompositionEngine() const;
+ void chooseCompositionStrategy() override;
+ compositionengine::Output::FrameFences presentAndGetFrameFences() override;
void dumpBase(std::string&) const;
private:
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 45b8308..1078f11 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -35,6 +35,16 @@
// If false, this output is not considered secure
bool isSecure{false};
+ // If true, the current frame on this output uses client composition
+ bool usesClientComposition{false};
+
+ // If true, the current frame on this output uses device composition
+ bool usesDeviceComposition{false};
+
+ // If true, the client target should be flipped when performing client
+ // composition
+ bool flipClientTarget{false};
+
// If true, this output displays layers that are internal-only
bool layerStackInternal{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
index 708f3a1..d8ad02a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayer.h
@@ -50,6 +50,12 @@
void updateCompositionState(bool) override;
void writeStateToHWC(bool) override;
+ HWC2::Layer* getHwcLayer() const override;
+ bool requiresClientComposition() const override;
+ void applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition) override;
+ void prepareForDeviceLayerRequests() override;
+ void applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) override;
+
void dump(std::string& result) const override;
virtual FloatRect calculateOutputSourceCrop() const;
@@ -66,6 +72,8 @@
void writeSidebandStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
void writeBufferStateToHWC(HWC2::Layer*, const LayerFECompositionState&);
void writeCompositionTypeToHWC(HWC2::Layer*, Hwc2::IComposerClient::Composition);
+ void detectDisallowedCompositionTypeChange(Hwc2::IComposerClient::Composition from,
+ Hwc2::IComposerClient::Composition to) const;
const compositionengine::Output& mOutput;
std::shared_ptr<compositionengine::Layer> mLayer;
@@ -79,4 +87,4 @@
std::shared_ptr<compositionengine::Layer>, sp<compositionengine::LayerFE>);
} // namespace impl
-} // namespace android::compositionengine
\ No newline at end of file
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
index e4c9c80..0a04462 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/RenderSurface.h
@@ -52,7 +52,7 @@
void setDisplaySize(const ui::Size&) override;
void setProtected(bool useProtected) override;
status_t beginFrame(bool mustRecompose) override;
- status_t prepareFrame() override;
+ void prepareFrame(bool usesClientComposition, bool usesDeviceComposition) override;
sp<GraphicBuffer> dequeueBuffer(base::unique_fd* bufferFence) override;
void queueBuffer(base::unique_fd&& readyFence) override;
void onPresentDisplayCompleted() override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
index 952f702..48c2dbf 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/LayerFE.h
@@ -33,6 +33,9 @@
MOCK_METHOD1(onPreComposition, bool(nsecs_t));
MOCK_CONST_METHOD2(latchCompositionState, void(LayerFECompositionState&, bool));
+ MOCK_METHOD1(prepareClientComposition,
+ std::optional<renderengine::LayerSettings>(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&));
MOCK_METHOD1(onLayerDisplayed, void(const sp<Fence>&));
MOCK_CONST_METHOD0(getDebugName, const char*());
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 924d72c..d494413 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -72,6 +72,13 @@
MOCK_METHOD1(setReleasedLayers, void(ReleasedLayers&&));
MOCK_METHOD0(takeReleasedLayers, ReleasedLayers());
+
+ MOCK_METHOD0(beginFrame, void());
+ MOCK_METHOD0(prepareFrame, void());
+ MOCK_METHOD0(chooseCompositionStrategy, void());
+
+ MOCK_METHOD0(postFramebuffer, void());
+ MOCK_METHOD0(presentAndGetFrameFences, compositionengine::Output::FrameFences());
};
} // namespace android::compositionengine::mock
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
index dab8b9d..195648f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/OutputLayer.h
@@ -41,6 +41,12 @@
MOCK_METHOD1(updateCompositionState, void(bool));
MOCK_METHOD1(writeStateToHWC, void(bool));
+ MOCK_CONST_METHOD0(getHwcLayer, HWC2::Layer*());
+ MOCK_CONST_METHOD0(requiresClientComposition, bool());
+ MOCK_METHOD1(applyDeviceCompositionTypeChange, void(Hwc2::IComposerClient::Composition));
+ MOCK_METHOD0(prepareForDeviceLayerRequests, void());
+ MOCK_METHOD1(applyDeviceLayerRequest, void(Hwc2::IComposerClient::LayerRequest request));
+
MOCK_CONST_METHOD1(dump, void(std::string&));
};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
index 146a2ea..ba6746a 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/RenderSurface.h
@@ -37,7 +37,7 @@
MOCK_METHOD1(setProtected, void(bool));
MOCK_METHOD1(setBufferDataspace, void(ui::Dataspace));
MOCK_METHOD1(beginFrame, status_t(bool mustRecompose));
- MOCK_METHOD0(prepareFrame, status_t());
+ MOCK_METHOD2(prepareFrame, void(bool, bool));
MOCK_METHOD1(dequeueBuffer, sp<GraphicBuffer>(base::unique_fd*));
MOCK_METHOD1(queueBuffer, void(base::unique_fd&&));
MOCK_METHOD0(onPresentDisplayCompleted, void());
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index 8520d70..6831901 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -21,13 +21,15 @@
#include <compositionengine/impl/Display.h>
#include <compositionengine/impl/DisplayColorProfile.h>
#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputLayer.h>
#include <compositionengine/impl/RenderSurface.h>
+#include <utils/Trace.h>
#include "DisplayHardware/HWComposer.h"
namespace android::compositionengine::impl {
-std::shared_ptr<compositionengine::Display> createDisplay(
+std::shared_ptr<Display> createDisplay(
const compositionengine::CompositionEngine& compositionEngine,
compositionengine::DisplayCreationArgs&& args) {
return std::make_shared<Display>(compositionEngine, std::move(args));
@@ -124,4 +126,118 @@
std::move(args)));
}
+void Display::chooseCompositionStrategy() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ // Default to the base settings -- client composition only.
+ Output::chooseCompositionStrategy();
+
+ // If we don't have a HWC display, then we are done
+ if (!mId) {
+ return;
+ }
+
+ // Get any composition changes requested by the HWC device, and apply them.
+ std::optional<android::HWComposer::DeviceRequestedChanges> changes;
+ auto& hwc = getCompositionEngine().getHwComposer();
+ if (status_t result = hwc.getDeviceCompositionChanges(*mId, anyLayersRequireClientComposition(),
+ &changes);
+ result != NO_ERROR) {
+ ALOGE("chooseCompositionStrategy failed for %s: %d (%s)", getName().c_str(), result,
+ strerror(-result));
+ return;
+ }
+ if (changes) {
+ applyChangedTypesToLayers(changes->changedTypes);
+ applyDisplayRequests(changes->displayRequests);
+ applyLayerRequestsToLayers(changes->layerRequests);
+ }
+
+ // Determine what type of composition we are doing from the final state
+ auto& state = editState();
+ state.usesClientComposition = anyLayersRequireClientComposition();
+ state.usesDeviceComposition = !allLayersRequireClientComposition();
+}
+
+bool Display::anyLayersRequireClientComposition() const {
+ const auto& layers = getOutputLayersOrderedByZ();
+ return std::any_of(layers.cbegin(), layers.cend(),
+ [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+bool Display::allLayersRequireClientComposition() const {
+ const auto& layers = getOutputLayersOrderedByZ();
+ return std::all_of(layers.cbegin(), layers.cend(),
+ [](const auto& layer) { return layer->requiresClientComposition(); });
+}
+
+void Display::applyChangedTypesToLayers(const ChangedTypes& changedTypes) {
+ if (changedTypes.empty()) {
+ return;
+ }
+
+ for (auto& layer : getOutputLayersOrderedByZ()) {
+ auto hwcLayer = layer->getHwcLayer();
+ if (!hwcLayer) {
+ continue;
+ }
+
+ if (auto it = changedTypes.find(hwcLayer); it != changedTypes.end()) {
+ layer->applyDeviceCompositionTypeChange(
+ static_cast<Hwc2::IComposerClient::Composition>(it->second));
+ }
+ }
+}
+
+void Display::applyDisplayRequests(const DisplayRequests& displayRequests) {
+ auto& state = editState();
+ state.flipClientTarget = (static_cast<uint32_t>(displayRequests) &
+ static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0;
+ // Note: HWC2::DisplayRequest::WriteClientTargetToOutput is currently ignored.
+}
+
+void Display::applyLayerRequestsToLayers(const LayerRequests& layerRequests) {
+ for (auto& layer : getOutputLayersOrderedByZ()) {
+ layer->prepareForDeviceLayerRequests();
+
+ auto hwcLayer = layer->getHwcLayer();
+ if (!hwcLayer) {
+ continue;
+ }
+
+ if (auto it = layerRequests.find(hwcLayer); it != layerRequests.end()) {
+ layer->applyDeviceLayerRequest(
+ static_cast<Hwc2::IComposerClient::LayerRequest>(it->second));
+ }
+ }
+}
+
+compositionengine::Output::FrameFences Display::presentAndGetFrameFences() {
+ auto result = impl::Output::presentAndGetFrameFences();
+
+ if (!mId) {
+ return result;
+ }
+
+ auto& hwc = getCompositionEngine().getHwComposer();
+ hwc.presentAndGetReleaseFences(*mId);
+
+ result.presentFence = hwc.getPresentFence(*mId);
+
+ // TODO(b/121291683): Change HWComposer call to return entire map
+ for (const auto& layer : getOutputLayersOrderedByZ()) {
+ auto hwcLayer = layer->getHwcLayer();
+ if (!hwcLayer) {
+ continue;
+ }
+
+ result.layerFences.emplace(hwcLayer, hwc.getLayerReleaseFence(*mId, hwcLayer));
+ }
+
+ hwc.clearReleaseFences(*mId);
+
+ return result;
+}
+
} // namespace android::compositionengine::impl
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 845e3c6..b411e0a 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -22,6 +22,7 @@
#include <compositionengine/impl/Output.h>
#include <compositionengine/impl/OutputLayer.h>
#include <ui/DebugUtils.h>
+#include <utils/Trace.h>
namespace android::compositionengine {
@@ -250,9 +251,115 @@
return std::move(mReleasedLayers);
}
+void Output::beginFrame() {
+ const bool dirty = !getDirtyRegion(false).isEmpty();
+ const bool empty = mOutputLayersOrderedByZ.empty();
+ const bool wasEmpty = !mState.lastCompositionHadVisibleLayers;
+
+ // If nothing has changed (!dirty), don't recompose.
+ // If something changed, but we don't currently have any visible layers,
+ // and didn't when we last did a composition, then skip it this time.
+ // The second rule does two things:
+ // - When all layers are removed from a display, we'll emit one black
+ // frame, then nothing more until we get new layers.
+ // - When a display is created with a private layer stack, we won't
+ // emit any black frames until a layer is added to the layer stack.
+ const bool mustRecompose = dirty && !(empty && wasEmpty);
+
+ const char flagPrefix[] = {'-', '+'};
+ static_cast<void>(flagPrefix);
+ ALOGV_IF("%s: %s composition for %s (%cdirty %cempty %cwasEmpty)", __FUNCTION__,
+ mustRecompose ? "doing" : "skipping", getName().c_str(), flagPrefix[dirty],
+ flagPrefix[empty], flagPrefix[wasEmpty]);
+
+ mRenderSurface->beginFrame(mustRecompose);
+
+ if (mustRecompose) {
+ mState.lastCompositionHadVisibleLayers = !empty;
+ }
+}
+
+void Output::prepareFrame() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (!mState.isEnabled) {
+ return;
+ }
+
+ chooseCompositionStrategy();
+
+ mRenderSurface->prepareFrame(mState.usesClientComposition, mState.usesDeviceComposition);
+}
+
+void Output::postFramebuffer() {
+ ATRACE_CALL();
+ ALOGV(__FUNCTION__);
+
+ if (!getState().isEnabled) {
+ return;
+ }
+
+ mRenderSurface->onPresentDisplayCompleted();
+
+ auto frame = presentAndGetFrameFences();
+
+ for (auto& layer : getOutputLayersOrderedByZ()) {
+ // The layer buffer from the previous frame (if any) is released
+ // by HWC only when the release fence from this frame (if any) is
+ // signaled. Always get the release fence from HWC first.
+ sp<Fence> releaseFence = Fence::NO_FENCE;
+
+ if (auto hwcLayer = layer->getHwcLayer()) {
+ if (auto f = frame.layerFences.find(hwcLayer); f != frame.layerFences.end()) {
+ releaseFence = f->second;
+ }
+ }
+
+ // If the layer was client composited in the previous frame, we
+ // need to merge with the previous client target acquire fence.
+ // Since we do not track that, always merge with the current
+ // client target acquire fence when it is available, even though
+ // this is suboptimal.
+ // TODO(b/121291683): Track previous frame client target acquire fence.
+ if (mState.usesClientComposition) {
+ releaseFence =
+ Fence::merge("LayerRelease", releaseFence, frame.clientTargetAcquireFence);
+ }
+
+ layer->getLayerFE().onLayerDisplayed(releaseFence);
+ }
+
+ // We've got a list of layers needing fences, that are disjoint with
+ // getOutputLayersOrderedByZ. The best we can do is to
+ // supply them with the present fence.
+ for (auto& weakLayer : mReleasedLayers) {
+ if (auto layer = weakLayer.promote(); layer != nullptr) {
+ layer->onLayerDisplayed(frame.presentFence);
+ }
+ }
+
+ // Clear out the released layers now that we're done with them.
+ mReleasedLayers.clear();
+}
+
void Output::dirtyEntireOutput() {
mState.dirtyRegion.set(mState.bounds);
}
+void Output::chooseCompositionStrategy() {
+ // The base output implementation can only do client composition
+ mState.usesClientComposition = true;
+ mState.usesDeviceComposition = false;
+}
+
+compositionengine::Output::FrameFences Output::presentAndGetFrameFences() {
+ compositionengine::Output::FrameFences result;
+ if (mState.usesClientComposition) {
+ result.clientTargetAcquireFence = mRenderSurface->getClientTargetAcquireFence();
+ }
+ return result;
+}
+
} // namespace impl
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 0b15dad..3e47fe2 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -24,6 +24,10 @@
dumpVal(out, "isEnabled", isEnabled);
dumpVal(out, "isSecure", isSecure);
+ dumpVal(out, "usesClientComposition", usesClientComposition);
+ dumpVal(out, "usesDeviceComposition", usesDeviceComposition);
+ dumpVal(out, "flipClientTarget", flipClientTarget);
+
dumpVal(out, "layerStack", layerStackId);
dumpVal(out, "layerStackInternal", layerStackInternal);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index ebfc704..6e744b9 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -550,6 +550,70 @@
}
}
+HWC2::Layer* OutputLayer::getHwcLayer() const {
+ return mState.hwc ? mState.hwc->hwcLayer.get() : nullptr;
+}
+
+bool OutputLayer::requiresClientComposition() const {
+ return !mState.hwc ||
+ mState.hwc->hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
+}
+
+void OutputLayer::detectDisallowedCompositionTypeChange(
+ Hwc2::IComposerClient::Composition from, Hwc2::IComposerClient::Composition to) const {
+ bool result = false;
+ switch (from) {
+ case Hwc2::IComposerClient::Composition::INVALID:
+ case Hwc2::IComposerClient::Composition::CLIENT:
+ result = false;
+ break;
+
+ case Hwc2::IComposerClient::Composition::DEVICE:
+ case Hwc2::IComposerClient::Composition::SOLID_COLOR:
+ result = (to == Hwc2::IComposerClient::Composition::CLIENT);
+ break;
+
+ case Hwc2::IComposerClient::Composition::CURSOR:
+ case Hwc2::IComposerClient::Composition::SIDEBAND:
+ result = (to == Hwc2::IComposerClient::Composition::CLIENT ||
+ to == Hwc2::IComposerClient::Composition::DEVICE);
+ break;
+ }
+
+ if (!result) {
+ ALOGE("[%s] Invalid device requested composition type change: %s (%d) --> %s (%d)",
+ mLayerFE->getDebugName(), toString(from).c_str(), static_cast<int>(from),
+ toString(to).c_str(), static_cast<int>(to));
+ }
+}
+
+void OutputLayer::applyDeviceCompositionTypeChange(
+ Hwc2::IComposerClient::Composition compositionType) {
+ LOG_FATAL_IF(!mState.hwc);
+ auto& hwcState = *mState.hwc;
+
+ detectDisallowedCompositionTypeChange(hwcState.hwcCompositionType, compositionType);
+
+ hwcState.hwcCompositionType = compositionType;
+}
+
+void OutputLayer::prepareForDeviceLayerRequests() {
+ mState.clearClientTarget = false;
+}
+
+void OutputLayer::applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest request) {
+ switch (request) {
+ case Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET:
+ mState.clearClientTarget = true;
+ break;
+
+ default:
+ ALOGE("[%s] Unknown device layer request %s (%d)", mLayerFE->getDebugName(),
+ toString(request).c_str(), static_cast<int>(request));
+ break;
+ }
+}
+
void OutputLayer::dump(std::string& out) const {
using android::base::StringAppendF;
diff --git a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
index 8a91316..1ce6b4c 100644
--- a/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/RenderSurface.cpp
@@ -23,6 +23,7 @@
#include <compositionengine/DisplaySurface.h>
#include <compositionengine/RenderSurfaceCreationArgs.h>
#include <compositionengine/impl/DumpHelpers.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/RenderSurface.h>
#include <log/log.h>
#include <renderengine/RenderEngine.h>
@@ -110,24 +111,13 @@
return mDisplaySurface->beginFrame(mustRecompose);
}
-status_t RenderSurface::prepareFrame() {
- auto& hwc = mCompositionEngine.getHwComposer();
- const auto id = mDisplay.getId();
- if (id) {
- status_t error = hwc.prepare(*id, mDisplay);
- if (error != NO_ERROR) {
- return error;
- }
- }
-
+void RenderSurface::prepareFrame(bool usesClientComposition, bool usesDeviceComposition) {
DisplaySurface::CompositionType compositionType;
- const bool hasClient = hwc.hasClientComposition(id);
- const bool hasDevice = hwc.hasDeviceComposition(id);
- if (hasClient && hasDevice) {
+ if (usesClientComposition && usesDeviceComposition) {
compositionType = DisplaySurface::COMPOSITION_MIXED;
- } else if (hasClient) {
+ } else if (usesClientComposition) {
compositionType = DisplaySurface::COMPOSITION_GLES;
- } else if (hasDevice) {
+ } else if (usesDeviceComposition) {
compositionType = DisplaySurface::COMPOSITION_HWC;
} else {
// Nothing to do -- when turning the screen off we get a frame like
@@ -135,7 +125,11 @@
// will do a prepare/set cycle.
compositionType = DisplaySurface::COMPOSITION_HWC;
}
- return mDisplaySurface->prepareFrame(compositionType);
+
+ if (status_t result = mDisplaySurface->prepareFrame(compositionType); result != NO_ERROR) {
+ ALOGE("updateCompositionType failed for %s: %d (%s)", mDisplay.getName().c_str(), result,
+ strerror(-result));
+ }
}
sp<GraphicBuffer> RenderSurface::dequeueBuffer(base::unique_fd* bufferFence) {
@@ -163,10 +157,9 @@
}
void RenderSurface::queueBuffer(base::unique_fd&& readyFence) {
- auto& hwc = mCompositionEngine.getHwComposer();
- const auto id = mDisplay.getId();
+ auto& state = mDisplay.getState();
- if (hwc.hasClientComposition(id) || hwc.hasFlipClientTargetRequest(id)) {
+ if (state.usesClientComposition || state.flipClientTarget) {
// hasFlipClientTargetRequest could return true even if we haven't
// dequeued a buffer before. Try dequeueing one if we don't have a
// buffer ready.
diff --git a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
index f0aea25..e3be0d7 100644
--- a/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/DisplayTest.cpp
@@ -24,33 +24,54 @@
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/NativeWindow.h>
+#include <compositionengine/mock/OutputLayer.h>
#include <compositionengine/mock/RenderSurface.h>
#include <gtest/gtest.h>
+#include "MockHWC2.h"
#include "MockHWComposer.h"
namespace android::compositionengine {
namespace {
using testing::_;
+using testing::DoAll;
using testing::Return;
using testing::ReturnRef;
+using testing::Sequence;
+using testing::SetArgPointee;
using testing::StrictMock;
constexpr DisplayId DEFAULT_DISPLAY_ID = DisplayId{42};
-class DisplayTest : public testing::Test {
-public:
- ~DisplayTest() override = default;
+struct DisplayTest : public testing::Test {
+ DisplayTest() {
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ EXPECT_CALL(*mLayer1, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer1));
+ EXPECT_CALL(*mLayer2, getHwcLayer()).WillRepeatedly(Return(&mHWC2Layer2));
+ EXPECT_CALL(*mLayer3, getHwcLayer()).WillRepeatedly(Return(nullptr));
+
+ std::vector<std::unique_ptr<OutputLayer>> layers;
+ layers.emplace_back(mLayer1);
+ layers.emplace_back(mLayer2);
+ layers.emplace_back(mLayer3);
+ mDisplay.setOutputLayersOrderedByZ(std::move(layers));
+ }
StrictMock<android::mock::HWComposer> mHwComposer;
StrictMock<mock::CompositionEngine> mCompositionEngine;
sp<mock::NativeWindow> mNativeWindow = new StrictMock<mock::NativeWindow>();
+ StrictMock<HWC2::mock::Layer> mHWC2Layer1;
+ StrictMock<HWC2::mock::Layer> mHWC2Layer2;
+ StrictMock<HWC2::mock::Layer> mHWC2LayerUnknown;
+ mock::OutputLayer* mLayer1 = new StrictMock<mock::OutputLayer>();
+ mock::OutputLayer* mLayer2 = new StrictMock<mock::OutputLayer>();
+ mock::OutputLayer* mLayer3 = new StrictMock<mock::OutputLayer>();
impl::Display mDisplay{mCompositionEngine,
DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
};
-/* ------------------------------------------------------------------------
+/*
* Basic construction
*/
@@ -90,13 +111,11 @@
}
}
-/* ------------------------------------------------------------------------
+/*
* Display::disconnect()
*/
TEST_F(DisplayTest, disconnectDisconnectsDisplay) {
- EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
-
// The first call to disconnect will disconnect the display with the HWC and
// set mHwcId to -1.
EXPECT_CALL(mHwComposer, disconnectDisplay(DEFAULT_DISPLAY_ID)).Times(1);
@@ -109,7 +128,7 @@
EXPECT_FALSE(mDisplay.getId());
}
-/* ------------------------------------------------------------------------
+/*
* Display::setColorTransform()
*/
@@ -117,8 +136,6 @@
// Identity matrix sets an identity state value
const mat4 identity;
- EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
-
EXPECT_CALL(mHwComposer, setColorTransform(DEFAULT_DISPLAY_ID, identity)).Times(1);
mDisplay.setColorTransform(identity);
@@ -135,7 +152,7 @@
EXPECT_EQ(HAL_COLOR_TRANSFORM_ARBITRARY_MATRIX, mDisplay.getState().colorTransform);
}
-/* ------------------------------------------------------------------------
+/*
* Display::setColorMode()
*/
@@ -145,7 +162,6 @@
mock::DisplayColorProfile* colorProfile = new StrictMock<mock::DisplayColorProfile>();
mDisplay.setDisplayColorProfileForTest(std::unique_ptr<DisplayColorProfile>(colorProfile));
- EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
EXPECT_CALL(*colorProfile, getTargetDataspace(_, _, _))
.WillRepeatedly(Return(ui::Dataspace::UNKNOWN));
@@ -202,7 +218,7 @@
EXPECT_EQ(ui::Dataspace::UNKNOWN, mDisplay.getState().targetDataspace);
}
-/* ------------------------------------------------------------------------
+/*
* Display::createDisplayColorProfile()
*/
@@ -214,7 +230,7 @@
EXPECT_TRUE(mDisplay.getDisplayColorProfile() != nullptr);
}
-/* ------------------------------------------------------------------------
+/*
* Display::createRenderSurface()
*/
@@ -225,5 +241,266 @@
EXPECT_TRUE(mDisplay.getRenderSurface() != nullptr);
}
+/*
+ * Display::chooseCompositionStrategy()
+ */
+
+struct DisplayChooseCompositionStrategyTest : public testing::Test {
+ struct DisplayPartialMock : public impl::Display {
+ DisplayPartialMock(const compositionengine::CompositionEngine& compositionEngine,
+ compositionengine::DisplayCreationArgs&& args)
+ : impl::Display(compositionEngine, std::move(args)) {}
+
+ // Sets up the helper functions called by chooseCompositionStrategy to
+ // use a mock implementations.
+ MOCK_CONST_METHOD0(anyLayersRequireClientComposition, bool());
+ MOCK_CONST_METHOD0(allLayersRequireClientComposition, bool());
+ MOCK_METHOD1(applyChangedTypesToLayers, void(const impl::Display::ChangedTypes&));
+ MOCK_METHOD1(applyDisplayRequests, void(const impl::Display::DisplayRequests&));
+ MOCK_METHOD1(applyLayerRequestsToLayers, void(const impl::Display::LayerRequests&));
+ };
+
+ DisplayChooseCompositionStrategyTest() {
+ EXPECT_CALL(mCompositionEngine, getHwComposer()).WillRepeatedly(ReturnRef(mHwComposer));
+ }
+
+ StrictMock<android::mock::HWComposer> mHwComposer;
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ StrictMock<DisplayPartialMock>
+ mDisplay{mCompositionEngine,
+ DisplayCreationArgsBuilder().setDisplayId(DEFAULT_DISPLAY_ID).build()};
+};
+
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutIfNotAHwcDisplay) {
+ impl::Display nonHwcDisplay{mCompositionEngine, DisplayCreationArgsBuilder().build()};
+ EXPECT_FALSE(nonHwcDisplay.getId());
+
+ nonHwcDisplay.chooseCompositionStrategy();
+
+ auto& state = nonHwcDisplay.getState();
+ EXPECT_TRUE(state.usesClientComposition);
+ EXPECT_FALSE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, takesEarlyOutOnHwcError) {
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, false, _))
+ .WillOnce(Return(INVALID_OPERATION));
+
+ mDisplay.chooseCompositionStrategy();
+
+ auto& state = mDisplay.getState();
+ EXPECT_TRUE(state.usesClientComposition);
+ EXPECT_FALSE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperation) {
+ // Since two calls are made to anyLayersRequireClientComposition with different return values,
+ // use a Sequence to control the matching so the values are returned in a known order.
+ Sequence s;
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(false));
+
+ EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _))
+ .WillOnce(Return(NO_ERROR));
+ EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+ mDisplay.chooseCompositionStrategy();
+
+ auto& state = mDisplay.getState();
+ EXPECT_FALSE(state.usesClientComposition);
+ EXPECT_TRUE(state.usesDeviceComposition);
+}
+
+TEST_F(DisplayChooseCompositionStrategyTest, normalOperationWithChanges) {
+ android::HWComposer::DeviceRequestedChanges changes{
+ {{nullptr, HWC2::Composition::Client}},
+ HWC2::DisplayRequest::FlipClientTarget,
+ {{nullptr, HWC2::LayerRequest::ClearClientTarget}},
+ };
+
+ // Since two calls are made to anyLayersRequireClientComposition with different return values,
+ // use a Sequence to control the matching so the values are returned in a known order.
+ Sequence s;
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition()).InSequence(s).WillOnce(Return(true));
+ EXPECT_CALL(mDisplay, anyLayersRequireClientComposition())
+ .InSequence(s)
+ .WillOnce(Return(false));
+
+ EXPECT_CALL(mHwComposer, getDeviceCompositionChanges(DEFAULT_DISPLAY_ID, true, _))
+ .WillOnce(DoAll(SetArgPointee<2>(changes), Return(NO_ERROR)));
+ EXPECT_CALL(mDisplay, applyChangedTypesToLayers(changes.changedTypes)).Times(1);
+ EXPECT_CALL(mDisplay, applyDisplayRequests(changes.displayRequests)).Times(1);
+ EXPECT_CALL(mDisplay, applyLayerRequestsToLayers(changes.layerRequests)).Times(1);
+ EXPECT_CALL(mDisplay, allLayersRequireClientComposition()).WillOnce(Return(false));
+
+ mDisplay.chooseCompositionStrategy();
+
+ auto& state = mDisplay.getState();
+ EXPECT_FALSE(state.usesClientComposition);
+ EXPECT_TRUE(state.usesDeviceComposition);
+}
+
+/*
+ * Display::anyLayersRequireClientComposition()
+ */
+
+TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsFalse) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(false));
+
+ EXPECT_FALSE(mDisplay.anyLayersRequireClientComposition());
+}
+
+TEST_F(DisplayTest, anyLayersRequireClientCompositionReturnsTrue) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(false));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+
+ EXPECT_TRUE(mDisplay.anyLayersRequireClientComposition());
+}
+
+/*
+ * Display::allLayersRequireClientComposition()
+ */
+
+TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsTrue) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer3, requiresClientComposition()).WillOnce(Return(true));
+
+ EXPECT_TRUE(mDisplay.allLayersRequireClientComposition());
+}
+
+TEST_F(DisplayTest, allLayersRequireClientCompositionReturnsFalse) {
+ EXPECT_CALL(*mLayer1, requiresClientComposition()).WillOnce(Return(true));
+ EXPECT_CALL(*mLayer2, requiresClientComposition()).WillOnce(Return(false));
+
+ EXPECT_FALSE(mDisplay.allLayersRequireClientComposition());
+}
+
+/*
+ * Display::applyChangedTypesToLayers()
+ */
+
+TEST_F(DisplayTest, applyChangedTypesToLayersTakesEarlyOutIfNoChangedLayers) {
+ mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes());
+}
+
+TEST_F(DisplayTest, applyChangedTypesToLayersAppliesChanges) {
+ EXPECT_CALL(*mLayer1,
+ applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT))
+ .Times(1);
+ EXPECT_CALL(*mLayer2,
+ applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::DEVICE))
+ .Times(1);
+
+ mDisplay.applyChangedTypesToLayers(impl::Display::ChangedTypes{
+ {&mHWC2Layer1, HWC2::Composition::Client},
+ {&mHWC2Layer2, HWC2::Composition::Device},
+ {&mHWC2LayerUnknown, HWC2::Composition::SolidColor},
+ });
+}
+
+/*
+ * Display::applyDisplayRequests()
+ */
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesNoRequests) {
+ mDisplay.applyDisplayRequests(static_cast<HWC2::DisplayRequest>(0));
+
+ auto& state = mDisplay.getState();
+ EXPECT_FALSE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesFlipClientTarget) {
+ mDisplay.applyDisplayRequests(HWC2::DisplayRequest::FlipClientTarget);
+
+ auto& state = mDisplay.getState();
+ EXPECT_TRUE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesWriteClientTargetToOutput) {
+ mDisplay.applyDisplayRequests(HWC2::DisplayRequest::WriteClientTargetToOutput);
+
+ auto& state = mDisplay.getState();
+ EXPECT_FALSE(state.flipClientTarget);
+}
+
+TEST_F(DisplayTest, applyDisplayRequestsToLayersHandlesAllRequestFlagsSet) {
+ mDisplay.applyDisplayRequests(static_cast<HWC2::DisplayRequest>(~0));
+
+ auto& state = mDisplay.getState();
+ EXPECT_TRUE(state.flipClientTarget);
+}
+
+/*
+ * Display::applyLayerRequestsToLayers()
+ */
+
+TEST_F(DisplayTest, applyLayerRequestsToLayersPreparesAllLayers) {
+ EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+
+ mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests());
+}
+
+TEST_F(DisplayTest, applyLayerRequestsToLayers2) {
+ EXPECT_CALL(*mLayer1, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer2, prepareForDeviceLayerRequests()).Times(1);
+ EXPECT_CALL(*mLayer3, prepareForDeviceLayerRequests()).Times(1);
+
+ EXPECT_CALL(*mLayer1,
+ applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET))
+ .Times(1);
+
+ mDisplay.applyLayerRequestsToLayers(impl::Display::LayerRequests{
+ {&mHWC2Layer1, HWC2::LayerRequest::ClearClientTarget},
+ {&mHWC2LayerUnknown, HWC2::LayerRequest::ClearClientTarget},
+ });
+}
+
+/*
+ * Display::presentAndGetFrameFences()
+ */
+
+TEST_F(DisplayTest, presentAndGetFrameFencesReturnsNoFencesOnNonHwcDisplay) {
+ auto nonHwcDisplay{
+ impl::createDisplay(mCompositionEngine, DisplayCreationArgsBuilder().build())};
+
+ auto result = nonHwcDisplay->presentAndGetFrameFences();
+
+ ASSERT_TRUE(result.presentFence.get());
+ EXPECT_FALSE(result.presentFence->isValid());
+ EXPECT_EQ(0u, result.layerFences.size());
+}
+
+TEST_F(DisplayTest, presentAndGetFrameFencesReturnsPresentAndLayerFences) {
+ sp<Fence> presentFence = new Fence();
+ sp<Fence> layer1Fence = new Fence();
+ sp<Fence> layer2Fence = new Fence();
+
+ EXPECT_CALL(mHwComposer, presentAndGetReleaseFences(DEFAULT_DISPLAY_ID)).Times(1);
+ EXPECT_CALL(mHwComposer, getPresentFence(DEFAULT_DISPLAY_ID)).WillOnce(Return(presentFence));
+ EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer1))
+ .WillOnce(Return(layer1Fence));
+ EXPECT_CALL(mHwComposer, getLayerReleaseFence(DEFAULT_DISPLAY_ID, &mHWC2Layer2))
+ .WillOnce(Return(layer2Fence));
+ EXPECT_CALL(mHwComposer, clearReleaseFences(DEFAULT_DISPLAY_ID)).Times(1);
+
+ auto result = mDisplay.presentAndGetFrameFences();
+
+ EXPECT_EQ(presentFence, result.presentFence);
+
+ EXPECT_EQ(2u, result.layerFences.size());
+ ASSERT_EQ(1, result.layerFences.count(&mHWC2Layer1));
+ EXPECT_EQ(layer1Fence, result.layerFences[&mHWC2Layer1]);
+ ASSERT_EQ(1, result.layerFences.count(&mHWC2Layer2));
+ EXPECT_EQ(layer2Fence, result.layerFences[&mHWC2Layer2]);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
index 94349de..5cfec77 100644
--- a/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
+++ b/services/surfaceflinger/CompositionEngine/tests/MockHWComposer.h
@@ -40,7 +40,9 @@
std::optional<DisplayId>(uint32_t, uint32_t, ui::PixelFormat*));
MOCK_METHOD1(createLayer, HWC2::Layer*(DisplayId));
MOCK_METHOD2(destroyLayer, void(DisplayId, HWC2::Layer*));
- MOCK_METHOD2(prepare, status_t(DisplayId, const compositionengine::Output&));
+ MOCK_METHOD3(getDeviceCompositionChanges,
+ status_t(DisplayId, bool,
+ std::optional<android::HWComposer::DeviceRequestedChanges>*));
MOCK_METHOD5(setClientTarget,
status_t(DisplayId, uint32_t, const sp<Fence>&, const sp<GraphicBuffer>&,
ui::Dataspace));
@@ -50,8 +52,6 @@
MOCK_METHOD2(setColorTransform, status_t(DisplayId, const mat4&));
MOCK_METHOD1(disconnectDisplay, void(DisplayId));
MOCK_CONST_METHOD1(hasDeviceComposition, bool(const std::optional<DisplayId>&));
- MOCK_CONST_METHOD1(hasFlipClientTargetRequest, bool(const std::optional<DisplayId>&));
- MOCK_CONST_METHOD1(hasClientComposition, bool(const std::optional<DisplayId>&));
MOCK_CONST_METHOD1(getPresentFence, sp<Fence>(DisplayId));
MOCK_CONST_METHOD2(getLayerReleaseFence, sp<Fence>(DisplayId, HWC2::Layer*));
MOCK_METHOD3(setOutputBuffer, status_t(DisplayId, const sp<Fence>&, const sp<GraphicBuffer>&));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 7b9528b..a5428ad 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -56,8 +56,7 @@
return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a;
}
-class OutputLayerTest : public testing::Test {
-public:
+struct OutputLayerTest : public testing::Test {
OutputLayerTest() {
EXPECT_CALL(*mLayerFE, getDebugName()).WillRepeatedly(Return("Test LayerFE"));
EXPECT_CALL(mOutput, getName()).WillRepeatedly(ReturnRef(kOutputName));
@@ -66,8 +65,6 @@
EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
}
- ~OutputLayerTest() override = default;
-
compositionengine::mock::Output mOutput;
std::shared_ptr<compositionengine::mock::Layer> mLayer{
new StrictMock<compositionengine::mock::Layer>()};
@@ -784,5 +781,99 @@
mOutputLayer.writeStateToHWC(false);
}
+/*
+ * OutputLayer::getHwcLayer()
+ */
+
+TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcState) {
+ mOutputLayer.editState().hwc.reset();
+
+ EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr);
+}
+
+TEST_F(OutputLayerTest, getHwcLayerHandlesNoHwcLayer) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+
+ EXPECT_TRUE(mOutputLayer.getHwcLayer() == nullptr);
+}
+
+TEST_F(OutputLayerTest, getHwcLayerReturnsHwcLayer) {
+ auto hwcLayer = std::make_shared<StrictMock<HWC2::mock::Layer>>();
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{hwcLayer};
+
+ EXPECT_EQ(hwcLayer.get(), mOutputLayer.getHwcLayer());
+}
+
+/*
+ * OutputLayer::requiresClientComposition()
+ */
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfNoHWC2State) {
+ mOutputLayer.editState().hwc.reset();
+
+ EXPECT_TRUE(mOutputLayer.requiresClientComposition());
+}
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsTrueIfSetToClientComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::CLIENT;
+
+ EXPECT_TRUE(mOutputLayer.requiresClientComposition());
+}
+
+TEST_F(OutputLayerTest, requiresClientCompositionReturnsFalseIfSetToDeviceComposition) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ EXPECT_FALSE(mOutputLayer.requiresClientComposition());
+}
+
+/*
+ * OutputLayer::applyDeviceCompositionTypeChange()
+ */
+
+TEST_F(OutputLayerTest, applyDeviceCompositionTypeChangeSetsNewType) {
+ mOutputLayer.editState().hwc = impl::OutputLayerCompositionState::Hwc{nullptr};
+ mOutputLayer.editState().hwc->hwcCompositionType = Hwc2::IComposerClient::Composition::DEVICE;
+
+ mOutputLayer.applyDeviceCompositionTypeChange(Hwc2::IComposerClient::Composition::CLIENT);
+
+ ASSERT_TRUE(mOutputLayer.getState().hwc);
+ EXPECT_EQ(Hwc2::IComposerClient::Composition::CLIENT,
+ mOutputLayer.getState().hwc->hwcCompositionType);
+}
+
+/*
+ * OutputLayer::prepareForDeviceLayerRequests()
+ */
+
+TEST_F(OutputLayerTest, prepareForDeviceLayerRequestsResetsRequestState) {
+ mOutputLayer.editState().clearClientTarget = true;
+
+ mOutputLayer.prepareForDeviceLayerRequests();
+
+ EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
+}
+
+/*
+ * OutputLayer::applyDeviceLayerRequest()
+ */
+
+TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesClearClientTarget) {
+ mOutputLayer.editState().clearClientTarget = false;
+
+ mOutputLayer.applyDeviceLayerRequest(Hwc2::IComposerClient::LayerRequest::CLEAR_CLIENT_TARGET);
+
+ EXPECT_TRUE(mOutputLayer.getState().clearClientTarget);
+}
+
+TEST_F(OutputLayerTest, applyDeviceLayerRequestHandlesUnknownRequest) {
+ mOutputLayer.editState().clearClientTarget = false;
+
+ mOutputLayer.applyDeviceLayerRequest(static_cast<Hwc2::IComposerClient::LayerRequest>(0));
+
+ EXPECT_FALSE(mOutputLayer.getState().clearClientTarget);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 6f087d9..aa35d25 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -17,6 +17,7 @@
#include <cmath>
#include <compositionengine/impl/Output.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/DisplayColorProfile.h>
#include <compositionengine/mock/Layer.h>
@@ -37,8 +38,7 @@
using testing::ReturnRef;
using testing::StrictMock;
-class OutputTest : public testing::Test {
-public:
+struct OutputTest : public testing::Test {
OutputTest() {
mOutput.setDisplayColorProfileForTest(
std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
@@ -46,7 +46,6 @@
mOutput.editState().bounds = kDefaultDisplaySize;
}
- ~OutputTest() override = default;
static const Rect kDefaultDisplaySize;
@@ -58,7 +57,7 @@
const Rect OutputTest::kDefaultDisplaySize{100, 200};
-/* ------------------------------------------------------------------------
+/*
* Basic construction
*/
@@ -77,7 +76,7 @@
EXPECT_FALSE(mOutput.isValid());
}
-/* ------------------------------------------------------------------------
+/*
* Output::setCompositionEnabled()
*/
@@ -108,7 +107,7 @@
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setProjection()
*/
@@ -130,7 +129,7 @@
EXPECT_EQ(needsFiltering, mOutput.getState().needsFiltering);
}
-/* ------------------------------------------------------------------------
+/*
* Output::setBounds()
*/
@@ -147,7 +146,7 @@
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setLayerStackFilter()
*/
@@ -161,7 +160,7 @@
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setColorTransform
*/
@@ -200,7 +199,7 @@
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region(kDefaultDisplaySize)));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setColorMode
*/
@@ -239,7 +238,7 @@
EXPECT_THAT(mOutput.getState().dirtyRegion, RegionEq(Region()));
}
-/* ------------------------------------------------------------------------
+/*
* Output::setRenderSurface()
*/
@@ -254,7 +253,7 @@
EXPECT_EQ(Rect(newDisplaySize), mOutput.getState().bounds);
}
-/* ------------------------------------------------------------------------
+/*
* Output::getDirtyRegion()
*/
@@ -283,7 +282,7 @@
}
}
-/* ------------------------------------------------------------------------
+/*
* Output::belongsInOutput()
*/
@@ -310,7 +309,7 @@
EXPECT_FALSE(mOutput.belongsInOutput(layerStack2, false));
}
-/* ------------------------------------------------------------------------
+/*
* Output::getOutputLayerForLayer()
*/
@@ -342,7 +341,7 @@
EXPECT_EQ(nullptr, mOutput.getOutputLayerForLayer(&layer));
}
-/* ------------------------------------------------------------------------
+/*
* Output::getOrCreateOutputLayer()
*/
@@ -389,5 +388,63 @@
}
}
+/*
+ * Output::prepareFrame()
+ */
+
+struct OutputPrepareFrameTest : public testing::Test {
+ struct OutputPartialMock : public impl::Output {
+ OutputPartialMock(const compositionengine::CompositionEngine& compositionEngine)
+ : impl::Output(compositionEngine) {}
+
+ // Sets up the helper functions called by prepareFrame to use a mock
+ // implementations.
+ MOCK_METHOD0(chooseCompositionStrategy, void());
+ };
+
+ OutputPrepareFrameTest() {
+ mOutput.setDisplayColorProfileForTest(
+ std::unique_ptr<DisplayColorProfile>(mDisplayColorProfile));
+ mOutput.setRenderSurfaceForTest(std::unique_ptr<RenderSurface>(mRenderSurface));
+ }
+
+ StrictMock<mock::CompositionEngine> mCompositionEngine;
+ mock::DisplayColorProfile* mDisplayColorProfile = new StrictMock<mock::DisplayColorProfile>();
+ mock::RenderSurface* mRenderSurface = new StrictMock<mock::RenderSurface>();
+ StrictMock<OutputPartialMock> mOutput{mCompositionEngine};
+};
+
+TEST_F(OutputPrepareFrameTest, takesEarlyOutIfNotEnabled) {
+ mOutput.editState().isEnabled = false;
+
+ mOutput.prepareFrame();
+}
+
+TEST_F(OutputPrepareFrameTest, delegatesToChooseCompositionStrategyAndRenderSurface) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+
+ EXPECT_CALL(mOutput, chooseCompositionStrategy()).Times(1);
+ EXPECT_CALL(*mRenderSurface, prepareFrame(false, true));
+
+ mOutput.prepareFrame();
+}
+
+// Note: Use OutputTest and not OutputPrepareFrameTest, so the real
+// base chooseCompositionStrategy() is invoked.
+TEST_F(OutputTest, prepareFrameSetsClientCompositionOnlyByDefault) {
+ mOutput.editState().isEnabled = true;
+ mOutput.editState().usesClientComposition = false;
+ mOutput.editState().usesDeviceComposition = true;
+
+ EXPECT_CALL(*mRenderSurface, prepareFrame(true, false));
+
+ mOutput.prepareFrame();
+
+ EXPECT_TRUE(mOutput.getState().usesClientComposition);
+ EXPECT_FALSE(mOutput.getState().usesDeviceComposition);
+}
+
} // namespace
} // namespace android::compositionengine
diff --git a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
index 87419ea..da3f4fb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/RenderSurfaceTest.cpp
@@ -18,6 +18,7 @@
#include <cstdint>
#include <compositionengine/RenderSurfaceCreationArgs.h>
+#include <compositionengine/impl/OutputCompositionState.h>
#include <compositionengine/impl/RenderSurface.h>
#include <compositionengine/mock/CompositionEngine.h>
#include <compositionengine/mock/Display.h>
@@ -27,15 +28,9 @@
#include <gtest/gtest.h>
#include <renderengine/mock/RenderEngine.h>
-#include "MockHWComposer.h"
-
namespace android::compositionengine {
namespace {
-/* ------------------------------------------------------------------------
- * RenderSurfaceTest
- */
-
constexpr int32_t DEFAULT_DISPLAY_WIDTH = 1920;
constexpr int32_t DEFAULT_DISPLAY_HEIGHT = 1080;
constexpr std::optional<DisplayId> DEFAULT_DISPLAY_ID = std::make_optional(DisplayId{123u});
@@ -55,14 +50,11 @@
RenderSurfaceTest() {
EXPECT_CALL(mDisplay, getId()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_ID));
EXPECT_CALL(mDisplay, getName()).WillRepeatedly(ReturnRef(DEFAULT_DISPLAY_NAME));
- EXPECT_CALL(mCompositionEngine, getHwComposer).WillRepeatedly(ReturnRef(mHwComposer));
EXPECT_CALL(mCompositionEngine, getRenderEngine).WillRepeatedly(ReturnRef(mRenderEngine));
EXPECT_CALL(*mNativeWindow, disconnect(NATIVE_WINDOW_API_EGL))
.WillRepeatedly(Return(NO_ERROR));
}
- ~RenderSurfaceTest() override = default;
- StrictMock<android::mock::HWComposer> mHwComposer;
StrictMock<renderengine::mock::RenderEngine> mRenderEngine;
StrictMock<mock::CompositionEngine> mCompositionEngine;
StrictMock<mock::Display> mDisplay;
@@ -74,7 +66,7 @@
mDisplaySurface}};
};
-/* ------------------------------------------------------------------------
+/*
* Basic construction
*/
@@ -82,7 +74,7 @@
EXPECT_TRUE(mSurface.isValid());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::initialize()
*/
@@ -95,7 +87,7 @@
mSurface.initialize();
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::getSize()
*/
@@ -105,7 +97,7 @@
EXPECT_EQ(expected, mSurface.getSize());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::getClientTargetAcquireFence()
*/
@@ -117,7 +109,7 @@
EXPECT_EQ(fence.get(), mSurface.getClientTargetAcquireFence().get());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::setDisplaySize()
*/
@@ -127,7 +119,7 @@
mSurface.setDisplaySize(ui::Size(640, 480));
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::setBufferDataspace()
*/
@@ -138,7 +130,7 @@
mSurface.setBufferDataspace(ui::Dataspace::DISPLAY_P3);
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::setProtected()
*/
@@ -179,7 +171,7 @@
EXPECT_FALSE(mSurface.isProtected());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::beginFrame()
*/
@@ -189,73 +181,39 @@
EXPECT_EQ(NO_ERROR, mSurface.beginFrame(true));
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::prepareFrame()
*/
-TEST_F(RenderSurfaceTest, prepareFramePassesOutputLayersToHwc) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(INVALID_OPERATION));
-
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
-}
-
-TEST_F(RenderSurfaceTest, prepareFrameTakesEarlyOutOnHwcError) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(INVALID_OPERATION));
-
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
-}
-
TEST_F(RenderSurfaceTest, prepareFrameHandlesMixedComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_MIXED))
- .WillOnce(Return(INVALID_OPERATION));
+ .WillOnce(Return(NO_ERROR));
- EXPECT_EQ(INVALID_OPERATION, mSurface.prepareFrame());
+ mSurface.prepareFrame(true, true);
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyGlesComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_GLES))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+ mSurface.prepareFrame(true, false);
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesOnlyHwcComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+ mSurface.prepareFrame(false, true);
}
TEST_F(RenderSurfaceTest, prepareFrameHandlesNoComposition) {
- EXPECT_CALL(mHwComposer, prepare(*DEFAULT_DISPLAY_ID, Ref(mDisplay)))
- .WillOnce(Return(NO_ERROR));
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasDeviceComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
-
EXPECT_CALL(*mDisplaySurface, prepareFrame(DisplaySurface::COMPOSITION_HWC))
.WillOnce(Return(NO_ERROR));
- EXPECT_EQ(NO_ERROR, mSurface.prepareFrame());
+ mSurface.prepareFrame(false, false);
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::dequeueBuffer()
*/
@@ -272,7 +230,7 @@
EXPECT_EQ(buffer.get(), mSurface.mutableGraphicBufferForTest().get());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::queueBuffer()
*/
@@ -280,9 +238,11 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID))
- .WillOnce(Return(false));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = false;
+ state.flipClientTarget = false;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
mSurface.queueBuffer(base::unique_fd());
@@ -294,7 +254,11 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = true;
+ state.flipClientTarget = false;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
@@ -308,8 +272,11 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = false;
+ state.flipClientTarget = true;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
.WillOnce(Return(NO_ERROR));
EXPECT_CALL(*mDisplaySurface, advanceFrame()).Times(1);
@@ -322,8 +289,11 @@
TEST_F(RenderSurfaceTest, queueBufferHandlesFlipClientTargetRequestWithNoBufferYetDequeued) {
sp<GraphicBuffer> buffer = new GraphicBuffer();
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(false));
- EXPECT_CALL(mHwComposer, hasFlipClientTargetRequest(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = false;
+ state.flipClientTarget = true;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, dequeueBuffer(_, _))
.WillOnce(
DoAll(SetArgPointee<0>(buffer.get()), SetArgPointee<1>(-1), Return(NO_ERROR)));
@@ -340,7 +310,10 @@
sp<GraphicBuffer> buffer = new GraphicBuffer();
mSurface.mutableGraphicBufferForTest() = buffer;
- EXPECT_CALL(mHwComposer, hasClientComposition(DEFAULT_DISPLAY_ID)).WillOnce(Return(true));
+ impl::OutputCompositionState state;
+ state.usesClientComposition = true;
+
+ EXPECT_CALL(mDisplay, getState()).WillOnce(ReturnRef(state));
EXPECT_CALL(*mNativeWindow, queueBuffer(buffer->getNativeBuffer(), -1))
.WillOnce(Return(INVALID_OPERATION));
EXPECT_CALL(mDisplay, isVirtual()).WillOnce(Return(true));
@@ -353,7 +326,7 @@
EXPECT_EQ(nullptr, mSurface.mutableGraphicBufferForTest().get());
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::onPresentDisplayCompleted()
*/
@@ -363,7 +336,7 @@
mSurface.onPresentDisplayCompleted();
}
-/* ------------------------------------------------------------------------
+/*
* RenderSurface::flip()
*/
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 3a5f3fa..d40a38c 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -26,11 +26,6 @@
ContainerLayer::~ContainerLayer() = default;
-bool ContainerLayer::prepareClientLayer(const RenderArea&, const Region&, bool, Region&, const bool,
- renderengine::LayerSettings&) {
- return false;
-}
-
bool ContainerLayer::isVisible() const {
return false;
}
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 57267c7..a1607ff 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -34,14 +34,6 @@
bool canReceiveInput() const override;
bool isCreatedFromMainThread() const override { return true; }
-
- bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
-
-protected:
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer) override;
};
} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1099041..d480f7c 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -20,6 +20,8 @@
#define LOG_TAG "HWComposer"
#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+#include "HWComposer.h"
+
#include <compositionengine/Output.h>
#include <compositionengine/OutputLayer.h>
#include <compositionengine/impl/OutputLayerCompositionState.h>
@@ -29,12 +31,10 @@
#include <utils/Errors.h>
#include <utils/Trace.h>
-#include "HWComposer.h"
-#include "HWC2.h"
-#include "ComposerHal.h"
-
-#include "../Layer.h" // needed only for debugging
+#include "../Layer.h" // needed only for debugging
#include "../SurfaceFlinger.h"
+#include "ComposerHal.h"
+#include "HWC2.h"
#define LOG_HWC_DISPLAY_ERROR(hwcDisplayId, msg) \
ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
@@ -113,31 +113,6 @@
return mDisplayData.at(*displayId).hwcDisplay->getCapabilities().count(capability) > 0;
}
-void HWComposer::validateChange(HWC2::Composition from, HWC2::Composition to) {
- bool valid = true;
- switch (from) {
- case HWC2::Composition::Client:
- valid = false;
- break;
- case HWC2::Composition::Device:
- case HWC2::Composition::SolidColor:
- valid = (to == HWC2::Composition::Client);
- break;
- case HWC2::Composition::Cursor:
- case HWC2::Composition::Sideband:
- valid = (to == HWC2::Composition::Client ||
- to == HWC2::Composition::Device);
- break;
- default:
- break;
- }
-
- if (!valid) {
- ALOGE("Invalid layer type change: %s --> %s", to_string(from).c_str(),
- to_string(to).c_str());
- }
-}
-
std::optional<DisplayIdentificationInfo> HWComposer::onHotplug(hwc2_display_t hwcDisplayId,
HWC2::Connection connection) {
std::optional<DisplayIdentificationInfo> info;
@@ -399,7 +374,9 @@
return NO_ERROR;
}
-status_t HWComposer::prepare(DisplayId displayId, const compositionengine::Output& output) {
+status_t HWComposer::getDeviceCompositionChanges(
+ DisplayId displayId, bool frameUsesClientComposition,
+ std::optional<android::HWComposer::DeviceRequestedChanges>* outChanges) {
ATRACE_CALL();
RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
@@ -419,12 +396,8 @@
// composition. When there is client composition, since we haven't
// rendered to the client target yet, we should not attempt to skip
// validate.
- //
- // displayData.hasClientComposition hasn't been updated for this frame.
- // The check below is incorrect. We actually rely on HWC here to fall
- // back to validate when there is any client layer.
displayData.validateWasSkipped = false;
- if (!displayData.hasClientComposition) {
+ if (!frameUsesClientComposition) {
sp<Fence> outPresentFence;
uint32_t state = UINT32_MAX;
error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
@@ -449,58 +422,19 @@
RETURN_IF_HWC_ERROR_FOR("validate", error, displayId, BAD_INDEX);
}
- std::unordered_map<HWC2::Layer*, HWC2::Composition> changedTypes;
+ android::HWComposer::DeviceRequestedChanges::ChangedTypes changedTypes;
changedTypes.reserve(numTypes);
error = hwcDisplay->getChangedCompositionTypes(&changedTypes);
RETURN_IF_HWC_ERROR_FOR("getChangedCompositionTypes", error, displayId, BAD_INDEX);
- displayData.displayRequests = static_cast<HWC2::DisplayRequest>(0);
- std::unordered_map<HWC2::Layer*, HWC2::LayerRequest> layerRequests;
+ auto displayRequests = static_cast<HWC2::DisplayRequest>(0);
+ android::HWComposer::DeviceRequestedChanges::LayerRequests layerRequests;
layerRequests.reserve(numRequests);
- error = hwcDisplay->getRequests(&displayData.displayRequests,
- &layerRequests);
+ error = hwcDisplay->getRequests(&displayRequests, &layerRequests);
RETURN_IF_HWC_ERROR_FOR("getRequests", error, displayId, BAD_INDEX);
- displayData.hasClientComposition = false;
- displayData.hasDeviceComposition = false;
- for (auto& outputLayer : output.getOutputLayersOrderedByZ()) {
- auto& state = outputLayer->editState();
- LOG_FATAL_IF(!state.hwc.);
- auto hwcLayer = (*state.hwc).hwcLayer;
-
- if (auto it = changedTypes.find(hwcLayer.get()); it != changedTypes.end()) {
- auto newCompositionType = it->second;
- validateChange(static_cast<HWC2::Composition>((*state.hwc).hwcCompositionType),
- newCompositionType);
- (*state.hwc).hwcCompositionType =
- static_cast<Hwc2::IComposerClient::Composition>(newCompositionType);
- }
-
- switch ((*state.hwc).hwcCompositionType) {
- case Hwc2::IComposerClient::Composition::CLIENT:
- displayData.hasClientComposition = true;
- break;
- case Hwc2::IComposerClient::Composition::DEVICE:
- case Hwc2::IComposerClient::Composition::SOLID_COLOR:
- case Hwc2::IComposerClient::Composition::CURSOR:
- case Hwc2::IComposerClient::Composition::SIDEBAND:
- displayData.hasDeviceComposition = true;
- break;
- default:
- break;
- }
-
- state.clearClientTarget = false;
- if (auto it = layerRequests.find(hwcLayer.get()); it != layerRequests.end()) {
- auto request = it->second;
- if (request == HWC2::LayerRequest::ClearClientTarget) {
- state.clearClientTarget = true;
- } else {
- LOG_DISPLAY_ERROR(displayId,
- ("Unknown layer request " + to_string(request)).c_str());
- }
- }
- }
+ outChanges->emplace(DeviceRequestedChanges{std::move(changedTypes), std::move(displayRequests),
+ std::move(layerRequests)});
error = hwcDisplay->acceptChanges();
RETURN_IF_HWC_ERROR_FOR("acceptChanges", error, displayId, BAD_INDEX);
@@ -508,40 +442,6 @@
return NO_ERROR;
}
-bool HWComposer::hasDeviceComposition(const std::optional<DisplayId>& displayId) const {
- if (!displayId) {
- // Displays without a corresponding HWC display are never composed by
- // the device
- return false;
- }
-
- RETURN_IF_INVALID_DISPLAY(*displayId, false);
- return mDisplayData.at(*displayId).hasDeviceComposition;
-}
-
-bool HWComposer::hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const {
- if (!displayId) {
- // Displays without a corresponding HWC display are never composed by
- // the device
- return false;
- }
-
- RETURN_IF_INVALID_DISPLAY(*displayId, false);
- return ((static_cast<uint32_t>(mDisplayData.at(*displayId).displayRequests) &
- static_cast<uint32_t>(HWC2::DisplayRequest::FlipClientTarget)) != 0);
-}
-
-bool HWComposer::hasClientComposition(const std::optional<DisplayId>& displayId) const {
- if (!displayId) {
- // Displays without a corresponding HWC display are always composed by
- // the client
- return true;
- }
-
- RETURN_IF_INVALID_DISPLAY(*displayId, true);
- return mDisplayData.at(*displayId).hasClientComposition;
-}
-
sp<Fence> HWComposer::getPresentFence(DisplayId displayId) const {
RETURN_IF_INVALID_DISPLAY(displayId, Fence::NO_FENCE);
return mDisplayData.at(displayId).lastPresentFence;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index de863b8..e87c5c3 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -71,8 +71,26 @@
// Destroy a previously created layer
virtual void destroyLayer(DisplayId displayId, HWC2::Layer* layer) = 0;
- // Asks the HAL what it can do
- virtual status_t prepare(DisplayId displayId, const compositionengine::Output&) = 0;
+ struct DeviceRequestedChanges {
+ using ChangedTypes = std::unordered_map<HWC2::Layer*, HWC2::Composition>;
+ using DisplayRequests = HWC2::DisplayRequest;
+ using LayerRequests = std::unordered_map<HWC2::Layer*, HWC2::LayerRequest>;
+
+ ChangedTypes changedTypes;
+ DisplayRequests displayRequests;
+ LayerRequests layerRequests;
+ };
+
+ // Gets any required composition change requests from the HWC device.
+ //
+ // Note that frameUsesClientComposition must be set correctly based on
+ // whether the current frame appears to use client composition. If it is
+ // false some internal optimizations are allowed to present the display
+ // with fewer handshakes, but this does not work if client composition is
+ // expected.
+ virtual status_t getDeviceCompositionChanges(
+ DisplayId, bool frameUsesClientComposition,
+ std::optional<DeviceRequestedChanges>* outChanges) = 0;
virtual status_t setClientTarget(DisplayId displayId, uint32_t slot,
const sp<Fence>& acquireFence, const sp<GraphicBuffer>& target,
@@ -93,15 +111,6 @@
// reset state when an external, non-virtual display is disconnected
virtual void disconnectDisplay(DisplayId displayId) = 0;
- // does this display have layers handled by HWC
- virtual bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const = 0;
-
- // does this display have pending request to flip client target
- virtual bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const = 0;
-
- // does this display have layers handled by GLES
- virtual bool hasClientComposition(const std::optional<DisplayId>& displayId) const = 0;
-
// get the present fence received from the last call to present.
virtual sp<Fence> getPresentFence(DisplayId displayId) const = 0;
@@ -210,8 +219,9 @@
// Destroy a previously created layer
void destroyLayer(DisplayId displayId, HWC2::Layer* layer) override;
- // Asks the HAL what it can do
- status_t prepare(DisplayId displayId, const compositionengine::Output&) override;
+ status_t getDeviceCompositionChanges(
+ DisplayId, bool frameUsesClientComposition,
+ std::optional<DeviceRequestedChanges>* outChanges) override;
status_t setClientTarget(DisplayId displayId, uint32_t slot, const sp<Fence>& acquireFence,
const sp<GraphicBuffer>& target, ui::Dataspace dataspace) override;
@@ -231,15 +241,6 @@
// reset state when an external, non-virtual display is disconnected
void disconnectDisplay(DisplayId displayId) override;
- // does this display have layers handled by HWC
- bool hasDeviceComposition(const std::optional<DisplayId>& displayId) const override;
-
- // does this display have pending request to flip client target
- bool hasFlipClientTargetRequest(const std::optional<DisplayId>& displayId) const override;
-
- // does this display have layers handled by GLES
- bool hasClientComposition(const std::optional<DisplayId>& displayId) const override;
-
// get the present fence received from the last call to present.
sp<Fence> getPresentFence(DisplayId displayId) const override;
@@ -326,14 +327,10 @@
std::optional<DisplayIdentificationInfo> onHotplugConnect(hwc2_display_t hwcDisplayId);
- static void validateChange(HWC2::Composition from, HWC2::Composition to);
-
struct DisplayData {
bool isVirtual = false;
- bool hasClientComposition = false;
- bool hasDeviceComposition = false;
+
HWC2::Display* hwcDisplay = nullptr;
- HWC2::DisplayRequest displayRequests;
sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
buffer_handle_t outbufHandle = nullptr;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b5f0800..a2eeea5 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -153,7 +153,6 @@
mRemoteSyncPoints.clear();
{
- Mutex::Autolock pendingStateLock(mPendingStateMutex);
for (State pendingState : mPendingStates) {
pendingState.barrierLayer_legacy = nullptr;
}
@@ -459,6 +458,10 @@
}
}
+bool Layer::onPreComposition(nsecs_t) {
+ return false;
+}
+
void Layer::latchCompositionState(compositionengine::LayerFECompositionState& compositionState,
bool includeGeometry) const {
if (includeGeometry) {
@@ -508,54 +511,33 @@
// drawing...
// ---------------------------------------------------------------------------
-bool Layer::prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- return prepareClientLayer(renderArea, clip, false, clearRegion, supportProtectedContent, layer);
-}
+std::optional<renderengine::LayerSettings> Layer::prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings& targetSettings) {
+ if (!getCompositionLayer()) {
+ return {};
+ }
-bool Layer::prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer) {
- return prepareClientLayer(renderArea, Region(renderArea.getBounds()), useIdentityTransform,
- clearRegion, supportProtectedContent, layer);
-}
-
-bool Layer::prepareClientLayer(const RenderArea& /*renderArea*/, const Region& /*clip*/,
- bool useIdentityTransform, Region& /*clearRegion*/,
- const bool /*supportProtectedContent*/,
- renderengine::LayerSettings& layer) {
FloatRect bounds = getBounds();
half alpha = getAlpha();
- layer.geometry.boundaries = bounds;
- if (useIdentityTransform) {
- layer.geometry.positionTransform = mat4();
+ renderengine::LayerSettings layerSettings;
+ layerSettings.geometry.boundaries = bounds;
+ if (targetSettings.useIdentityTransform) {
+ layerSettings.geometry.positionTransform = mat4();
} else {
- const ui::Transform transform = getTransform();
- mat4 m;
- m[0][0] = transform[0][0];
- m[0][1] = transform[0][1];
- m[0][3] = transform[0][2];
- m[1][0] = transform[1][0];
- m[1][1] = transform[1][1];
- m[1][3] = transform[1][2];
- m[3][0] = transform[2][0];
- m[3][1] = transform[2][1];
- m[3][3] = transform[2][2];
- layer.geometry.positionTransform = m;
+ layerSettings.geometry.positionTransform = getTransform().asMatrix4();
}
if (hasColorTransform()) {
- layer.colorTransform = getColorTransform();
+ layerSettings.colorTransform = getColorTransform();
}
const auto roundedCornerState = getRoundedCornerState();
- layer.geometry.roundedCornersRadius = roundedCornerState.radius;
- layer.geometry.roundedCornersCrop = roundedCornerState.cropRect;
+ layerSettings.geometry.roundedCornersRadius = roundedCornerState.radius;
+ layerSettings.geometry.roundedCornersCrop = roundedCornerState.cropRect;
- layer.alpha = alpha;
- layer.sourceDataspace = mCurrentDataSpace;
- return true;
+ layerSettings.alpha = alpha;
+ layerSettings.sourceDataspace = mCurrentDataSpace;
+ return layerSettings;
}
Hwc2::IComposerClient::Composition Layer::getCompositionType(
@@ -853,6 +835,7 @@
// Commit the transaction
commitTransaction(c);
+ mPendingStatesSnapshot = mPendingStates;
mCurrentState.callbackHandles = {};
return flags;
}
@@ -1820,14 +1803,61 @@
setTransactionFlags(eTransactionNeeded);
}
-void Layer::writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet,
- uint32_t traceFlags) {
+void Layer::writeToProtoDrawingState(LayerProto* layerInfo, uint32_t traceFlags) const {
+ ui::Transform transform = getTransform();
+
+ if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
+ for (const auto& pendingState : mPendingStatesSnapshot) {
+ auto barrierLayer = pendingState.barrierLayer_legacy.promote();
+ if (barrierLayer != nullptr) {
+ BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
+ barrierLayerProto->set_id(barrierLayer->sequence);
+ barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
+ }
+ }
+
+ auto buffer = mActiveBuffer;
+ if (buffer != nullptr) {
+ LayerProtoHelper::writeToProto(buffer,
+ [&]() { return layerInfo->mutable_active_buffer(); });
+ LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
+ layerInfo->mutable_buffer_transform());
+ }
+ layerInfo->set_invalidate(contentDirty);
+ layerInfo->set_is_protected(isProtected());
+ layerInfo->set_dataspace(
+ dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
+ layerInfo->set_queued_frames(getQueuedFrameCount());
+ layerInfo->set_refresh_pending(isBufferLatched());
+ layerInfo->set_curr_frame(mCurrentFrameNumber);
+ layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
+
+ layerInfo->set_corner_radius(getRoundedCornerState().radius);
+ LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
+ LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
+ [&]() { return layerInfo->mutable_position(); });
+ LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
+ LayerProtoHelper::writeToProto(visibleRegion,
+ [&]() { return layerInfo->mutable_visible_region(); });
+ LayerProtoHelper::writeToProto(surfaceDamageRegion,
+ [&]() { return layerInfo->mutable_damage_region(); });
+ }
+
+ if (traceFlags & SurfaceTracing::TRACE_EXTRA) {
+ LayerProtoHelper::writeToProto(mSourceBounds,
+ [&]() { return layerInfo->mutable_source_bounds(); });
+ LayerProtoHelper::writeToProto(mScreenBounds,
+ [&]() { return layerInfo->mutable_screen_bounds(); });
+ }
+}
+
+void Layer::writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+ uint32_t traceFlags) const {
const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
const LayerVector& children = useDrawing ? mDrawingChildren : mCurrentChildren;
const State& state = useDrawing ? mDrawingState : mCurrentState;
ui::Transform requestedTransform = state.active_legacy.transform;
- ui::Transform transform = getTransform();
if (traceFlags & SurfaceTracing::TRACE_CRITICAL) {
layerInfo->set_id(sequence);
@@ -1847,17 +1877,10 @@
LayerProtoHelper::writeToProto(state.activeTransparentRegion_legacy,
[&]() { return layerInfo->mutable_transparent_region(); });
- LayerProtoHelper::writeToProto(visibleRegion,
- [&]() { return layerInfo->mutable_visible_region(); });
- LayerProtoHelper::writeToProto(surfaceDamageRegion,
- [&]() { return layerInfo->mutable_damage_region(); });
layerInfo->set_layer_stack(getLayerStack());
layerInfo->set_z(state.z);
- LayerProtoHelper::writePositionToProto(transform.tx(), transform.ty(),
- [&]() { return layerInfo->mutable_position(); });
-
LayerProtoHelper::writePositionToProto(requestedTransform.tx(), requestedTransform.ty(),
[&]() {
return layerInfo->mutable_requested_position();
@@ -1868,15 +1891,9 @@
LayerProtoHelper::writeToProto(state.crop_legacy,
[&]() { return layerInfo->mutable_crop(); });
- layerInfo->set_corner_radius(getRoundedCornerState().radius);
layerInfo->set_is_opaque(isOpaque(state));
- layerInfo->set_invalidate(contentDirty);
- layerInfo->set_is_protected(isProtected());
- // XXX (b/79210409) mCurrentDataSpace is not protected
- layerInfo->set_dataspace(
- dataspaceDetails(static_cast<android_dataspace>(mCurrentDataSpace)));
layerInfo->set_pixel_format(decodePixelFormat(getPixelFormat()));
LayerProtoHelper::writeToProto(getColor(), [&]() { return layerInfo->mutable_color(); });
@@ -1884,7 +1901,6 @@
[&]() { return layerInfo->mutable_requested_color(); });
layerInfo->set_flags(state.flags);
- LayerProtoHelper::writeToProto(transform, layerInfo->mutable_transform());
LayerProtoHelper::writeToProto(requestedTransform,
layerInfo->mutable_requested_transform());
@@ -1901,29 +1917,6 @@
} else {
layerInfo->set_z_order_relative_of(-1);
}
-
- auto buffer = mActiveBuffer;
- if (buffer != nullptr) {
- LayerProtoHelper::writeToProto(buffer,
- [&]() { return layerInfo->mutable_active_buffer(); });
- LayerProtoHelper::writeToProto(ui::Transform(mCurrentTransform),
- layerInfo->mutable_buffer_transform());
- }
-
- layerInfo->set_queued_frames(getQueuedFrameCount());
- layerInfo->set_refresh_pending(isBufferLatched());
- layerInfo->set_curr_frame(mCurrentFrameNumber);
- layerInfo->set_effective_scaling_mode(getEffectiveScalingMode());
-
- for (const auto& pendingState : mPendingStates) {
- auto barrierLayer = pendingState.barrierLayer_legacy.promote();
- if (barrierLayer != nullptr) {
- BarrierLayerProto* barrierLayerProto = layerInfo->add_barrier_layer();
- barrierLayerProto->set_id(barrierLayer->sequence);
- barrierLayerProto->set_frame_number(pendingState.frameNumber_legacy);
- }
- }
- LayerProtoHelper::writeToProto(mBounds, [&]() { return layerInfo->mutable_bounds(); });
}
if (traceFlags & SurfaceTracing::TRACE_INPUT) {
@@ -1936,23 +1929,19 @@
for (const auto& entry : state.metadata.mMap) {
(*protoMap)[entry.first] = std::string(entry.second.cbegin(), entry.second.cend());
}
- LayerProtoHelper::writeToProto(mEffectiveTransform,
- layerInfo->mutable_effective_transform());
- LayerProtoHelper::writeToProto(mSourceBounds,
- [&]() { return layerInfo->mutable_source_bounds(); });
- LayerProtoHelper::writeToProto(mScreenBounds,
- [&]() { return layerInfo->mutable_screen_bounds(); });
}
}
-void Layer::writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
- uint32_t traceFlags) {
+void Layer::writeToProtoCompositionState(LayerProto* layerInfo,
+ const sp<DisplayDevice>& displayDevice,
+ uint32_t traceFlags) const {
auto outputLayer = findOutputLayerForDisplay(displayDevice);
if (!outputLayer) {
return;
}
- writeToProto(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
+ writeToProtoDrawingState(layerInfo, traceFlags);
+ writeToProtoCommonState(layerInfo, LayerVector::StateSet::Drawing, traceFlags);
const auto& compositionState = outputLayer->getState();
@@ -1970,13 +1959,6 @@
static_cast<int32_t>(compositionState.hwc ? (*compositionState.hwc).hwcCompositionType
: Hwc2::IComposerClient::Composition::CLIENT);
layerInfo->set_hwc_composition_type(compositionType);
-
- if (std::strcmp(getTypeId(), "BufferLayer") == 0 &&
- static_cast<BufferLayer*>(this)->isProtected()) {
- layerInfo->set_is_protected(true);
- } else {
- layerInfo->set_is_protected(false);
- }
}
bool Layer::isRemovedFromCurrentState() const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 45199dd..953f25d 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -435,11 +435,21 @@
bool isRemovedFromCurrentState() const;
- void writeToProto(LayerProto* layerInfo, LayerVector::StateSet stateSet,
- uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
-
- void writeToProto(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
- uint32_t traceFlags = SurfaceTracing::TRACE_ALL);
+ // Write states that are modified by the main thread. This includes drawing
+ // state as well as buffer data. This should be called in the main or tracing
+ // thread.
+ void writeToProtoDrawingState(LayerProto* layerInfo,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ // Write states that are modified by the main thread. This includes drawing
+ // state as well as buffer data and composition data for layers on the specified
+ // display. This should be called in the main or tracing thread.
+ void writeToProtoCompositionState(LayerProto* layerInfo, const sp<DisplayDevice>& displayDevice,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ // Write drawing or current state. If writing current state, the caller should hold the
+ // external mStateLock. If writing drawing state, this function should be called on the
+ // main or tracing thread.
+ void writeToProtoCommonState(LayerProto* layerInfo, LayerVector::StateSet stateSet,
+ uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
virtual Geometry getActiveGeometry(const Layer::State& s) const { return s.active_legacy; }
virtual uint32_t getActiveWidth(const Layer::State& s) const { return s.active_legacy.w; }
@@ -451,19 +461,17 @@
return s.activeTransparentRegion_legacy;
}
virtual Rect getCrop(const Layer::State& s) const { return s.crop_legacy; }
-
-protected:
- virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
- bool useIdentityTransform, Region& clearRegion,
- const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
+ virtual bool needsFiltering(const sp<const DisplayDevice>&) const { return false; }
public:
/*
* compositionengine::LayerFE overrides
*/
+ bool onPreComposition(nsecs_t) override;
void latchCompositionState(compositionengine::LayerFECompositionState&,
bool includeGeometry) const override;
+ std::optional<renderengine::LayerSettings> prepareClientComposition(
+ compositionengine::LayerFE::ClientCompositionTargetSettings&) override;
void onLayerDisplayed(const sp<Fence>& releaseFence) override;
const char* getDebugName() const override;
@@ -499,17 +507,6 @@
virtual void releasePendingBuffer(nsecs_t /*dequeueReadyTime*/) { }
/*
- * prepareClientLayer - populates a renderengine::LayerSettings to passed to
- * RenderEngine::drawLayers. Returns true if the layer can be used, and
- * false otherwise.
- */
- bool prepareClientLayer(const RenderArea& renderArea, const Region& clip, Region& clearRegion,
- const bool supportProtectedContent, renderengine::LayerSettings& layer);
- bool prepareClientLayer(const RenderArea& renderArea, bool useIdentityTransform,
- Region& clearRegion, const bool supportProtectedContent,
- renderengine::LayerSettings& layer);
-
- /*
* doTransaction - process the transaction. This is a good place to figure
* out which attributes of the surface have changed.
*/
@@ -813,13 +810,15 @@
bool mPrimaryDisplayOnly = false;
- // these are protected by an external lock
- State mCurrentState;
+ // These are only accessed by the main thread or the tracing thread.
State mDrawingState;
- std::atomic<uint32_t> mTransactionFlags{0};
+ // Store a copy of the pending state so that the drawing thread can access the
+ // states without a lock.
+ Vector<State> mPendingStatesSnapshot;
- // Accessed from main thread and binder threads
- Mutex mPendingStateMutex;
+ // these are protected by an external lock (mStateLock)
+ State mCurrentState;
+ std::atomic<uint32_t> mTransactionFlags{0};
Vector<State> mPendingStates;
// Timestamp history for UIAutomation. Thread safe.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 7345e8d..d877e77 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1790,11 +1790,12 @@
mCompositionEngine->preComposition(refreshArgs);
rebuildLayerStacks();
calculateWorkingSet();
- for (const auto& [token, display] : mDisplays) {
- beginFrame(display);
- prepareFrame(display);
- doDebugFlashRegions(display, repaintEverything);
- doComposition(display, repaintEverything);
+ for (const auto& [token, displayDevice] : mDisplays) {
+ auto display = displayDevice->getCompositionDisplay();
+ display->beginFrame();
+ display->prepareFrame();
+ doDebugFlashRegions(displayDevice, repaintEverything);
+ doComposition(displayDevice, repaintEverything);
}
logLayerStats();
@@ -1802,16 +1803,16 @@
postFrame();
postComposition();
- mHadClientComposition = false;
- mHadDeviceComposition = false;
- for (const auto& [token, displayDevice] : mDisplays) {
- auto display = displayDevice->getCompositionDisplay();
- const auto displayId = display->getId();
- mHadClientComposition =
- mHadClientComposition || getHwComposer().hasClientComposition(displayId);
- mHadDeviceComposition =
- mHadDeviceComposition || getHwComposer().hasDeviceComposition(displayId);
- }
+ mHadClientComposition =
+ std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
+ auto& displayDevice = tokenDisplayPair.second;
+ return displayDevice->getCompositionDisplay()->getState().usesClientComposition;
+ });
+ mHadDeviceComposition =
+ std::any_of(mDisplays.cbegin(), mDisplays.cend(), [](const auto& tokenDisplayPair) {
+ auto& displayDevice = tokenDisplayPair.second;
+ return displayDevice->getCompositionDisplay()->getState().usesDeviceComposition;
+ });
mVSyncModulator->onRefreshed(mHadClientComposition);
@@ -1948,13 +1949,13 @@
}
}
- postFramebuffer(displayDevice);
+ displayDevice->getCompositionDisplay()->postFramebuffer();
if (mDebugRegion > 1) {
usleep(mDebugRegion * 1000);
}
- prepareFrame(displayDevice);
+ displayDevice->getCompositionDisplay()->prepareFrame();
}
void SurfaceFlinger::logLayerStats() {
@@ -2043,7 +2044,7 @@
getBE().mGlCompositionDoneTimeline.updateSignalTimes();
std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
- if (displayDevice && getHwComposer().hasClientComposition(displayDevice->getId())) {
+ if (displayDevice && displayDevice->getCompositionDisplay()->getState().usesClientComposition) {
glCompositionDoneFenceTime =
std::make_shared<FenceTime>(displayDevice->getCompositionDisplay()
->getRenderSurface()
@@ -2373,51 +2374,6 @@
profile->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
}
-void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& displayDevice) {
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- bool dirty = !display->getDirtyRegion(false).isEmpty();
- bool empty = displayDevice->getVisibleLayersSortedByZ().size() == 0;
- bool wasEmpty = !displayState.lastCompositionHadVisibleLayers;
-
- // If nothing has changed (!dirty), don't recompose.
- // If something changed, but we don't currently have any visible layers,
- // and didn't when we last did a composition, then skip it this time.
- // The second rule does two things:
- // - When all layers are removed from a display, we'll emit one black
- // frame, then nothing more until we get new layers.
- // - When a display is created with a private layer stack, we won't
- // emit any black frames until a layer is added to the layer stack.
- bool mustRecompose = dirty && !(empty && wasEmpty);
-
- const char flagPrefix[] = {'-', '+'};
- static_cast<void>(flagPrefix);
- ALOGV_IF(displayDevice->isVirtual(), "%s: %s composition for %s (%cdirty %cempty %cwasEmpty)",
- __FUNCTION__, mustRecompose ? "doing" : "skipping",
- displayDevice->getDebugName().c_str(), flagPrefix[dirty], flagPrefix[empty],
- flagPrefix[wasEmpty]);
-
- display->getRenderSurface()->beginFrame(mustRecompose);
-
- if (mustRecompose) {
- display->editState().lastCompositionHadVisibleLayers = !empty;
- }
-}
-
-void SurfaceFlinger::prepareFrame(const sp<DisplayDevice>& displayDevice) {
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
-
- if (!displayState.isEnabled) {
- return;
- }
-
- status_t result = display->getRenderSurface()->prepareFrame();
- ALOGE_IF(result != NO_ERROR, "prepareFrame failed for %s: %d (%s)",
- displayDevice->getDebugName().c_str(), result, strerror(-result));
-}
-
void SurfaceFlinger::doComposition(const sp<DisplayDevice>& displayDevice, bool repaintEverything) {
ATRACE_CALL();
ALOGV("doComposition");
@@ -2435,7 +2391,7 @@
display->editState().dirtyRegion.clear();
display->getRenderSurface()->flip();
}
- postFramebuffer(displayDevice);
+ displayDevice->getCompositionDisplay()->postFramebuffer();
}
void SurfaceFlinger::postFrame()
@@ -2450,68 +2406,6 @@
}
}
-void SurfaceFlinger::postFramebuffer(const sp<DisplayDevice>& displayDevice) {
- ATRACE_CALL();
- ALOGV("postFramebuffer");
-
- auto display = displayDevice->getCompositionDisplay();
- const auto& displayState = display->getState();
- const auto displayId = display->getId();
-
- if (displayState.isEnabled) {
- if (displayId) {
- getHwComposer().presentAndGetReleaseFences(*displayId);
- }
- display->getRenderSurface()->onPresentDisplayCompleted();
- for (auto& layer : display->getOutputLayersOrderedByZ()) {
- sp<Fence> releaseFence = Fence::NO_FENCE;
- bool usedClientComposition = true;
-
- // The layer buffer from the previous frame (if any) is released
- // by HWC only when the release fence from this frame (if any) is
- // signaled. Always get the release fence from HWC first.
- if (layer->getState().hwc) {
- const auto& hwcState = *layer->getState().hwc;
- releaseFence =
- getHwComposer().getLayerReleaseFence(*displayId, hwcState.hwcLayer.get());
- usedClientComposition =
- hwcState.hwcCompositionType == Hwc2::IComposerClient::Composition::CLIENT;
- }
-
- // If the layer was client composited in the previous frame, we
- // need to merge with the previous client target acquire fence.
- // Since we do not track that, always merge with the current
- // client target acquire fence when it is available, even though
- // this is suboptimal.
- if (usedClientComposition) {
- releaseFence =
- Fence::merge("LayerRelease", releaseFence,
- display->getRenderSurface()->getClientTargetAcquireFence());
- }
-
- layer->getLayerFE().onLayerDisplayed(releaseFence);
- }
-
- // We've got a list of layers needing fences, that are disjoint with
- // display->getVisibleLayersSortedByZ. The best we can do is to
- // supply them with the present fence.
- auto releasedLayers = display->takeReleasedLayers();
- if (!releasedLayers.empty()) {
- sp<Fence> presentFence =
- displayId ? getHwComposer().getPresentFence(*displayId) : Fence::NO_FENCE;
- for (auto& weakLayer : releasedLayers) {
- if (auto layer = weakLayer.promote(); layer != nullptr) {
- layer->onLayerDisplayed(presentFence);
- }
- }
- }
-
- if (displayId) {
- getHwComposer().clearReleaseFences(*displayId);
- }
- }
-}
-
void SurfaceFlinger::handleTransaction(uint32_t transactionFlags)
{
ATRACE_CALL();
@@ -3354,9 +3248,7 @@
const Region bounds(displayState.bounds);
const DisplayRenderArea renderArea(displayDevice);
const TracedOrdinal<bool> hasClientComposition = {"hasClientComposition",
- getHwComposer().hasClientComposition(
- displayId)};
-
+ displayState.usesClientComposition};
bool applyColorMatrix = false;
renderengine::DisplaySettings clientCompositionDisplay;
@@ -3409,7 +3301,7 @@
clientCompositionDisplay.maxLuminance =
profile->getHdrCapabilities().getDesiredMaxLuminance();
- const bool hasDeviceComposition = getHwComposer().hasDeviceComposition(displayId);
+ const bool hasDeviceComposition = displayState.usesDeviceComposition;
const bool skipClientColorTransform =
getHwComposer()
.hasDisplayCapability(displayId,
@@ -3427,6 +3319,7 @@
*/
ALOGV("Rendering client layers");
+ const bool useIdentityTransform = false;
bool firstLayer = true;
Region clearRegion = Region::INVALID_REGION;
for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
@@ -3447,13 +3340,20 @@
layer->getRoundedCornerState().radius == 0.0f && hasClientComposition) {
// never clear the very first layer since we're
// guaranteed the FB is already cleared
- renderengine::LayerSettings layerSettings;
Region dummyRegion;
- bool prepared =
- layer->prepareClientLayer(renderArea, clip, dummyRegion,
- supportProtectedContent, layerSettings);
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering(renderArea.getDisplayDevice()) ||
+ renderArea.needsFiltering(),
+ renderArea.isSecure(),
+ supportProtectedContent,
+ dummyRegion,
+ };
+ auto result = layer->prepareClientComposition(targetSettings);
- if (prepared) {
+ if (result) {
+ auto& layerSettings = *result;
layerSettings.source.buffer.buffer = nullptr;
layerSettings.source.solidColor = half3(0.0, 0.0, 0.0);
layerSettings.alpha = half(0.0);
@@ -3464,12 +3364,18 @@
break;
}
case Hwc2::IComposerClient::Composition::CLIENT: {
- renderengine::LayerSettings layerSettings;
- bool prepared =
- layer->prepareClientLayer(renderArea, clip, clearRegion,
- supportProtectedContent, layerSettings);
- if (prepared) {
- clientCompositionLayers.push_back(layerSettings);
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering(renderArea.getDisplayDevice()) ||
+ renderArea.needsFiltering(),
+ renderArea.isSecure(),
+ supportProtectedContent,
+ clearRegion,
+ };
+ auto result = layer->prepareClientComposition(targetSettings);
+ if (result) {
+ clientCompositionLayers.push_back(*result);
}
break;
}
@@ -4577,18 +4483,22 @@
if (const auto it = dumpers.find(flag); it != dumpers.end()) {
(it->second)(args, asProto, result);
- } else {
- if (asProto) {
- LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
- result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
- } else {
- dumpAllLocked(args, result);
- }
+ } else if (!asProto) {
+ dumpAllLocked(args, result);
}
if (locked) {
mStateLock.unlock();
}
+
+ LayersProto layersProto = dumpProtoFromMainThread();
+ if (asProto) {
+ result.append(layersProto.SerializeAsString().c_str(), layersProto.ByteSize());
+ } else {
+ auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+ result.append(LayerProtoParser::layerTreeToString(layerTree));
+ result.append("\n");
+ }
}
write(fd, result.c_str(), result.size());
return NO_ERROR;
@@ -4829,19 +4739,23 @@
result.append("\n");
}
-LayersProto SurfaceFlinger::dumpProtoInfo(LayerVector::StateSet stateSet,
- uint32_t traceFlags) const {
+LayersProto SurfaceFlinger::dumpDrawingStateProto(uint32_t traceFlags) const {
LayersProto layersProto;
- const bool useDrawing = stateSet == LayerVector::StateSet::Drawing;
- const State& state = useDrawing ? mDrawingState : mCurrentState;
- state.traverseInZOrder([&](Layer* layer) {
+ mDrawingState.traverseInZOrder([&](Layer* layer) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, stateSet, traceFlags);
+ layer->writeToProtoDrawingState(layerProto, traceFlags);
+ layer->writeToProtoCommonState(layerProto, LayerVector::StateSet::Drawing, traceFlags);
});
return layersProto;
}
+LayersProto SurfaceFlinger::dumpProtoFromMainThread(uint32_t traceFlags) {
+ LayersProto layersProto;
+ postMessageSync(new LambdaMessage([&]() { layersProto = dumpDrawingStateProto(traceFlags); }));
+ return layersProto;
+}
+
LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(
const sp<DisplayDevice>& displayDevice) const {
LayersProto layersProto;
@@ -4862,7 +4776,7 @@
mDrawingState.traverseInZOrder([&](Layer* layer) {
if (!layer->visibleRegion.isEmpty() && !display->getOutputLayersOrderedByZ().empty()) {
LayerProto* layerProto = layersProto.add_layers();
- layer->writeToProto(layerProto, displayDevice);
+ layer->writeToProtoCompositionState(layerProto, displayDevice);
}
});
@@ -4927,13 +4841,6 @@
colorizer.reset(result);
{
- LayersProto layersProto = dumpProtoInfo(LayerVector::StateSet::Current);
- auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
- result.append(LayerProtoParser::layerTreeToString(layerTree));
- result.append("\n");
- }
-
- {
StringAppendF(&result, "Composition layers\n");
mDrawingState.traverseInZOrder([&](Layer* layer) {
auto compositionLayer = layer->getCompositionLayer();
@@ -5049,19 +4956,6 @@
result.append("\n");
}
-const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
- // Note: mStateLock is held here
- for (const auto& [token, display] : mDisplays) {
- if (display->getId() == displayId) {
- return getDisplayDeviceLocked(token)->getVisibleLayersSortedByZ();
- }
- }
-
- ALOGE("%s: Invalid display %s", __FUNCTION__, to_string(displayId).c_str());
- static const Vector<sp<Layer>> empty;
- return empty;
-}
-
void SurfaceFlinger::updateColorMatrixLocked() {
mat4 colorMatrix;
if (mGlobalSaturationFactor != 1.0f) {
@@ -6022,11 +5916,19 @@
Region clearRegion = Region::INVALID_REGION;
traverseLayers([&](Layer* layer) {
- renderengine::LayerSettings layerSettings;
- bool prepared = layer->prepareClientLayer(renderArea, useIdentityTransform, clearRegion,
- false, layerSettings);
- if (prepared) {
- clientCompositionLayers.push_back(layerSettings);
+ const bool supportProtectedContent = false;
+ Region clip(renderArea.getBounds());
+ compositionengine::LayerFE::ClientCompositionTargetSettings targetSettings{
+ clip,
+ useIdentityTransform,
+ layer->needsFiltering(renderArea.getDisplayDevice()) || renderArea.needsFiltering(),
+ renderArea.isSecure(),
+ supportProtectedContent,
+ clearRegion,
+ };
+ auto result = layer->prepareClientComposition(targetSettings);
+ if (result) {
+ clientCompositionLayers.push_back(*result);
}
});
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 04e0c89..3974a8c 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -265,7 +265,8 @@
status_t postMessageAsync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
// post a synchronous message to the main thread
- status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0);
+ status_t postMessageSync(const sp<MessageBase>& msg, nsecs_t reltime = 0, uint32_t flags = 0)
+ EXCLUDES(mStateLock);
// force full composition on all displays
void repaintEverything();
@@ -304,10 +305,6 @@
// TODO: this should be made accessible only to MessageQueue
void onMessageReceived(int32_t what);
- // for debugging only
- // TODO: this should be made accessible only to HWComposer
- const Vector<sp<Layer>>& getLayerSortedByZForHwcDisplay(DisplayId displayId);
-
renderengine::RenderEngine& getRenderEngine() const;
bool authenticateSurfaceTextureLocked(
@@ -763,17 +760,6 @@
ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const;
void calculateWorkingSet();
- /*
- * beginFrame - This function handles any pre-frame processing that needs to be
- * prior to any CompositionInfo handling and is not dependent on data in
- * CompositionInfo
- */
- void beginFrame(const sp<DisplayDevice>& display);
- /* prepareFrame - This function will call into the DisplayDevice to prepare a
- * frame after CompositionInfo has been programmed. This provides a mechanism
- * to prepare the hardware composer
- */
- void prepareFrame(const sp<DisplayDevice>& display);
void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
void logLayerStats();
@@ -785,7 +771,6 @@
bool doComposeSurfaces(const sp<DisplayDevice>& display, const Region& debugRegionm,
base::unique_fd* readyFence);
- void postFramebuffer(const sp<DisplayDevice>& display);
void postFrame();
/* ------------------------------------------------------------------------
@@ -895,8 +880,9 @@
void dumpBufferingStats(std::string& result) const;
void dumpDisplayIdentificationData(std::string& result) const;
void dumpWideColorInfo(std::string& result) const;
- LayersProto dumpProtoInfo(LayerVector::StateSet stateSet,
- uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ LayersProto dumpDrawingStateProto(uint32_t traceFlags = SurfaceTracing::TRACE_ALL) const;
+ LayersProto dumpProtoFromMainThread(uint32_t traceFlags = SurfaceTracing::TRACE_ALL)
+ EXCLUDES(mStateLock);
void withTracingLock(std::function<void()> operation) REQUIRES(mStateLock);
LayersProto dumpVisibleLayersProtoInfo(const sp<DisplayDevice>& display) const;
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index c4ab066..9053f2c 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -162,7 +162,7 @@
LayersTraceProto entry;
entry.set_elapsed_realtime_nanos(elapsedRealtimeNano());
entry.set_where(where);
- LayersProto layers(mFlinger.dumpProtoInfo(LayerVector::StateSet::Drawing, mTraceFlags));
+ LayersProto layers(mFlinger.dumpDrawingStateProto(mTraceFlags));
entry.mutable_layers()->Swap(&layers);
return entry;
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 0f21ad8..47243a9 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -296,7 +296,6 @@
EXPECT_CALL(*test->mComposer,
setColorTransform(HWC_DISPLAY, _, Hwc2::ColorTransform::IDENTITY))
.Times(1);
- EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
EXPECT_CALL(*test->mComposer, getDisplayRequests(HWC_DISPLAY, _, _, _)).Times(1);
EXPECT_CALL(*test->mComposer, acceptDisplayChanges(HWC_DISPLAY)).Times(1);
EXPECT_CALL(*test->mComposer, presentDisplay(HWC_DISPLAY, _)).Times(1);
@@ -336,11 +335,21 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+
EXPECT_CALL(*test->mDisplaySurface,
prepareFrame(compositionengine::DisplaySurface::COMPOSITION_HWC))
.Times(1);
}
+ static void setupHwcClientCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, presentOrValidateDisplay(HWC_DISPLAY, _, _, _, _)).Times(1);
+ }
+
+ static void setupHwcForcedClientCompositionCallExpectations(CompositionTest* test) {
+ EXPECT_CALL(*test->mComposer, validateDisplay(HWC_DISPLAY, _, _)).Times(1);
+ }
+
static void setupRECompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mDisplaySurface,
prepareFrame(compositionengine::DisplaySurface::COMPOSITION_GLES))
@@ -414,6 +423,8 @@
}
static void setupHwcCompositionCallExpectations(CompositionTest*) {}
+ static void setupHwcClientCompositionCallExpectations(CompositionTest*) {}
+ static void setupHwcForcedClientCompositionCallExpectations(CompositionTest*) {}
static void setupRECompositionCallExpectations(CompositionTest* test) {
EXPECT_CALL(*test->mRenderEngine, useNativeFenceSync()).WillRepeatedly(Return(true));
@@ -981,12 +992,13 @@
template <typename Case>
static void setupCallExpectations(CompositionTest* test) {
Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcClientCompositionCallExpectations(test);
Case::Display::setupRECompositionCallExpectations(test);
Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
}
};
-struct ForcedClientCompositionResultVariant : public RECompositionResultVariant {
+struct ForcedClientCompositionResultVariant : public CompositionResultBaseVariant {
static void setupLayerState(CompositionTest* test, sp<Layer> layer) {
const auto outputLayer = layer->findOutputLayerForDisplay(test->mDisplay);
LOG_FATAL_IF(!outputLayer);
@@ -994,6 +1006,14 @@
}
template <typename Case>
+ static void setupCallExpectations(CompositionTest* test) {
+ Case::Display::setupNonEmptyFrameCompositionCallExpectations(test);
+ Case::Display::setupHwcForcedClientCompositionCallExpectations(test);
+ Case::Display::setupRECompositionCallExpectations(test);
+ Case::Display::template setupRELayerCompositionCallExpectations<Case>(test);
+ }
+
+ template <typename Case>
static void setupCallExpectationsForDirtyGeometry(CompositionTest*) {}
template <typename Case>
diff --git a/vulkan/vkjson/vkjson.cc b/vulkan/vkjson/vkjson.cc
index 3da4336..6204779 100644
--- a/vulkan/vkjson/vkjson.cc
+++ b/vulkan/vkjson/vkjson.cc
@@ -21,11 +21,14 @@
#include "vkjson.h"
#include <assert.h>
-#include <string.h>
#include <stdlib.h>
+#include <string.h>
-#include <cmath>
+#include <json/json.h>
+
+#include <algorithm>
#include <cinttypes>
+#include <cmath>
#include <cstdio>
#include <limits>
#include <memory>
@@ -33,8 +36,6 @@
#include <type_traits>
#include <utility>
-#include <json/json.h>
-
namespace {
inline bool IsIntegral(double value) {
@@ -46,6 +47,14 @@
#endif
}
+// Floating point fields of Vulkan structure use single precision. The string
+// output of max double value in c++ will be larger than Java double's infinity
+// value. Below fake double max/min values are only to serve the safe json text
+// parsing in between C++ and Java, becasue Java json library simply cannot
+// handle infinity.
+static const double SAFE_DOUBLE_MAX = 0.99 * std::numeric_limits<double>::max();
+static const double SAFE_DOUBLE_MIN = 0.99 * std::numeric_limits<double>::min();
+
template <typename T> struct EnumTraits;
template <> struct EnumTraits<VkPhysicalDeviceType> {
static uint32_t min() { return VK_PHYSICAL_DEVICE_TYPE_BEGIN_RANGE; }
@@ -851,7 +860,8 @@
template <typename T, typename = EnableForArithmetic<T>>
inline Json::Value ToJsonValue(const T& value) {
- return Json::Value(static_cast<double>(value));
+ return Json::Value(
+ std::clamp(static_cast<double>(value), SAFE_DOUBLE_MIN, SAFE_DOUBLE_MAX));
}
inline Json::Value ToJsonValue(const uint64_t& value) {