Merge "Fix flaky RefreshRateStatsTests"
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 37ff442..347856d 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -61,7 +61,6 @@
// Default mode.
const int BUGREPORT_MODE_DEFAULT = 6;
- // TODO(b/111441001): Should the args be for the consuming application rather than triggering?
/*
* Starts a bugreport in the background.
*
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index a3f8755..8b33a56 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -63,6 +63,26 @@
return ret;
}
+std::string Status::exceptionToString(int32_t exceptionCode) {
+ switch (exceptionCode) {
+ #define EXCEPTION_TO_CASE(EXCEPTION) case EXCEPTION: return #EXCEPTION;
+ EXCEPTION_TO_CASE(EX_NONE)
+ EXCEPTION_TO_CASE(EX_SECURITY)
+ EXCEPTION_TO_CASE(EX_BAD_PARCELABLE)
+ EXCEPTION_TO_CASE(EX_ILLEGAL_ARGUMENT)
+ EXCEPTION_TO_CASE(EX_NULL_POINTER)
+ EXCEPTION_TO_CASE(EX_ILLEGAL_STATE)
+ EXCEPTION_TO_CASE(EX_NETWORK_MAIN_THREAD)
+ EXCEPTION_TO_CASE(EX_UNSUPPORTED_OPERATION)
+ EXCEPTION_TO_CASE(EX_SERVICE_SPECIFIC)
+ EXCEPTION_TO_CASE(EX_PARCELABLE)
+ EXCEPTION_TO_CASE(EX_HAS_REPLY_HEADER)
+ EXCEPTION_TO_CASE(EX_TRANSACTION_FAILED)
+ #undef EXCEPTION_TO_CASE
+ default: return std::to_string(exceptionCode);
+ }
+}
+
Status::Status(int32_t exceptionCode, int32_t errorCode)
: mException(exceptionCode),
mErrorCode(errorCode) {}
@@ -184,7 +204,7 @@
if (mException == EX_NONE) {
ret.append("No error");
} else {
- ret.appendFormat("Status(%d): '", mException);
+ ret.appendFormat("Status(%d, %s): '", mException, exceptionToString(mException).c_str());
if (mException == EX_SERVICE_SPECIFIC ||
mException == EX_TRANSACTION_FAILED) {
ret.appendFormat("%d: ", mErrorCode);
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 1674516..aa44285 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -143,6 +143,9 @@
* dies. The @a cookie is optional. If non-NULL, you can
* supply a NULL @a recipient, and the recipient previously
* added with that cookie will be unlinked.
+ *
+ * If the binder is dead, this will return DEAD_OBJECT. Deleting
+ * the object will also unlink all death recipients.
*/
// NOLINTNEXTLINE(google-default-arguments)
virtual status_t unlinkToDeath( const wp<DeathRecipient>& recipient,
diff --git a/libs/binder/include/binder/Status.h b/libs/binder/include/binder/Status.h
index c3738f8..7d889b6 100644
--- a/libs/binder/include/binder/Status.h
+++ b/libs/binder/include/binder/Status.h
@@ -22,6 +22,7 @@
#include <binder/Parcel.h>
#include <utils/String8.h>
+#include <string>
namespace android {
namespace binder {
@@ -97,6 +98,8 @@
static Status fromStatusT(status_t status);
+ static std::string exceptionToString(status_t exceptionCode);
+
Status() = default;
~Status() = default;
diff --git a/libs/binder/ndk/ibinder.cpp b/libs/binder/ndk/ibinder.cpp
index bdbc0d3..bd6886d 100644
--- a/libs/binder/ndk/ibinder.cpp
+++ b/libs/binder/ndk/ibinder.cpp
@@ -269,6 +269,18 @@
CHECK(who == mWho);
mOnDied(mCookie);
+
+ sp<AIBinder_DeathRecipient> recipient = mParentRecipient.promote();
+ sp<IBinder> strongWho = who.promote();
+
+ // otherwise this will be cleaned up later with pruneDeadTransferEntriesLocked
+ if (recipient != nullptr && strongWho != nullptr) {
+ status_t result = recipient->unlinkToDeath(strongWho, mCookie);
+ if (result != ::android::DEAD_OBJECT) {
+ LOG(WARNING) << "Unlinking to dead binder resulted in: " << result;
+ }
+ }
+
mWho = nullptr;
}
@@ -277,24 +289,34 @@
CHECK(onDied != nullptr);
}
-binder_status_t AIBinder_DeathRecipient::linkToDeath(AIBinder* binder, void* cookie) {
+void AIBinder_DeathRecipient::pruneDeadTransferEntriesLocked() {
+ mDeathRecipients.erase(std::remove_if(mDeathRecipients.begin(), mDeathRecipients.end(),
+ [](const sp<TransferDeathRecipient>& tdr) {
+ return tdr->getWho() == nullptr;
+ }),
+ mDeathRecipients.end());
+}
+
+binder_status_t AIBinder_DeathRecipient::linkToDeath(sp<IBinder> binder, void* cookie) {
CHECK(binder != nullptr);
std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
sp<TransferDeathRecipient> recipient =
- new TransferDeathRecipient(binder->getBinder(), cookie, mOnDied);
+ new TransferDeathRecipient(binder, cookie, this, mOnDied);
- status_t status = binder->getBinder()->linkToDeath(recipient, cookie, 0 /*flags*/);
+ status_t status = binder->linkToDeath(recipient, cookie, 0 /*flags*/);
if (status != STATUS_OK) {
return PruneStatusT(status);
}
mDeathRecipients.push_back(recipient);
+
+ pruneDeadTransferEntriesLocked();
return STATUS_OK;
}
-binder_status_t AIBinder_DeathRecipient::unlinkToDeath(AIBinder* binder, void* cookie) {
+binder_status_t AIBinder_DeathRecipient::unlinkToDeath(sp<IBinder> binder, void* cookie) {
CHECK(binder != nullptr);
std::lock_guard<std::mutex> l(mDeathRecipientsMutex);
@@ -302,10 +324,10 @@
for (auto it = mDeathRecipients.rbegin(); it != mDeathRecipients.rend(); ++it) {
sp<TransferDeathRecipient> recipient = *it;
- if (recipient->getCookie() == cookie && recipient->getWho() == binder->getBinder()) {
+ if (recipient->getCookie() == cookie && recipient->getWho() == binder) {
mDeathRecipients.erase(it.base() - 1);
- status_t status = binder->getBinder()->unlinkToDeath(recipient, cookie, 0 /*flags*/);
+ status_t status = binder->unlinkToDeath(recipient, cookie, 0 /*flags*/);
if (status != ::android::OK) {
LOG(ERROR) << __func__
<< ": removed reference to death recipient but unlink failed.";
@@ -390,7 +412,7 @@
}
// returns binder_status_t
- return recipient->linkToDeath(binder, cookie);
+ return recipient->linkToDeath(binder->getBinder(), cookie);
}
binder_status_t AIBinder_unlinkToDeath(AIBinder* binder, AIBinder_DeathRecipient* recipient,
@@ -401,7 +423,7 @@
}
// returns binder_status_t
- return recipient->unlinkToDeath(binder, cookie);
+ return recipient->unlinkToDeath(binder->getBinder(), cookie);
}
uid_t AIBinder_getCallingUid() {
@@ -555,9 +577,15 @@
LOG(ERROR) << __func__ << ": requires non-null onBinderDied parameter.";
return nullptr;
}
- return new AIBinder_DeathRecipient(onBinderDied);
+ auto ret = new AIBinder_DeathRecipient(onBinderDied);
+ ret->incStrong(nullptr);
+ return ret;
}
void AIBinder_DeathRecipient_delete(AIBinder_DeathRecipient* recipient) {
- delete recipient;
+ if (recipient == nullptr) {
+ return;
+ }
+
+ recipient->decStrong(nullptr);
}
diff --git a/libs/binder/ndk/ibinder_internal.h b/libs/binder/ndk/ibinder_internal.h
index 202d6d2..5cb68c2 100644
--- a/libs/binder/ndk/ibinder_internal.h
+++ b/libs/binder/ndk/ibinder_internal.h
@@ -128,13 +128,14 @@
//
// When the AIBinder_DeathRecipient is dropped, so are the actual underlying death recipients. When
// the IBinder dies, only a wp to it is kept.
-struct AIBinder_DeathRecipient {
+struct AIBinder_DeathRecipient : ::android::RefBase {
// One of these is created for every linkToDeath. This is to be able to recover data when a
// binderDied receipt only gives us information about the IBinder.
struct TransferDeathRecipient : ::android::IBinder::DeathRecipient {
TransferDeathRecipient(const ::android::wp<::android::IBinder>& who, void* cookie,
+ const ::android::wp<AIBinder_DeathRecipient>& parentRecipient,
const AIBinder_DeathRecipient_onBinderDied onDied)
- : mWho(who), mCookie(cookie), mOnDied(onDied) {}
+ : mWho(who), mCookie(cookie), mParentRecipient(parentRecipient), mOnDied(onDied) {}
void binderDied(const ::android::wp<::android::IBinder>& who) override;
@@ -144,14 +145,24 @@
private:
::android::wp<::android::IBinder> mWho;
void* mCookie;
+
+ ::android::wp<AIBinder_DeathRecipient> mParentRecipient;
+
+ // This is kept separately from AIBinder_DeathRecipient in case the death recipient is
+ // deleted while the death notification is fired
const AIBinder_DeathRecipient_onBinderDied mOnDied;
};
explicit AIBinder_DeathRecipient(AIBinder_DeathRecipient_onBinderDied onDied);
- binder_status_t linkToDeath(AIBinder* binder, void* cookie);
- binder_status_t unlinkToDeath(AIBinder* binder, void* cookie);
+ binder_status_t linkToDeath(::android::sp<::android::IBinder>, void* cookie);
+ binder_status_t unlinkToDeath(::android::sp<::android::IBinder> binder, void* cookie);
private:
+ // When the user of this API deletes a Bp object but not the death recipient, the
+ // TransferDeathRecipient object can't be cleaned up. This is called whenever a new
+ // TransferDeathRecipient is linked, and it ensures that mDeathRecipients can't grow unbounded.
+ void pruneDeadTransferEntriesLocked();
+
std::mutex mDeathRecipientsMutex;
std::vector<::android::sp<TransferDeathRecipient>> mDeathRecipients;
AIBinder_DeathRecipient_onBinderDied mOnDied;
diff --git a/libs/binder/ndk/include_ndk/android/binder_ibinder.h b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
index bddc10d..80d1254 100644
--- a/libs/binder/ndk/include_ndk/android/binder_ibinder.h
+++ b/libs/binder/ndk/include_ndk/android/binder_ibinder.h
@@ -301,6 +301,11 @@
* may return a binder transaction failure and in case the death recipient cannot be found, it
* returns STATUS_NAME_NOT_FOUND.
*
+ * This only ever needs to be called when the AIBinder_DeathRecipient remains for use with other
+ * AIBinder objects. If the death recipient is deleted, all binders will automatically be unlinked.
+ * If the binder dies, it will automatically unlink. If the binder is deleted, it will be
+ * automatically unlinked.
+ *
* \param binder the binder object to remove a previously linked death recipient from.
* \param recipient the callback to remove.
* \param cookie the cookie used to link to death.
diff --git a/libs/binder/ndk/test/main_client.cpp b/libs/binder/ndk/test/main_client.cpp
index bff601e..8467734 100644
--- a/libs/binder/ndk/test/main_client.cpp
+++ b/libs/binder/ndk/test/main_client.cpp
@@ -86,12 +86,15 @@
// the binder driver should return this if the service dies during the transaction
EXPECT_EQ(STATUS_DEAD_OBJECT, foo->die());
+ foo = nullptr;
+ AIBinder_decStrong(binder);
+ binder = nullptr;
+
std::unique_lock<std::mutex> lock(deathMutex);
EXPECT_TRUE(deathCv.wait_for(lock, 1s, [&] { return deathRecieved; }));
EXPECT_TRUE(deathRecieved);
AIBinder_DeathRecipient_delete(recipient);
- AIBinder_decStrong(binder);
}
TEST(NdkBinder, RetrieveNonNdkService) {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 0510492..4c2e653 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -31,44 +31,7 @@
"-Werror",
],
cppflags: [
- "-Weverything",
-
- // The static constructors and destructors in this library have not been noted to
- // introduce significant overheads
- "-Wno-exit-time-destructors",
- "-Wno-global-constructors",
-
- // We only care about compiling as C++14
- "-Wno-c++98-compat-pedantic",
-
- // We don't need to enumerate every case in a switch as long as a default case
- // is present
- "-Wno-switch-enum",
-
- // Allow calling variadic macros without a __VA_ARGS__ list
- "-Wno-gnu-zero-variadic-macro-arguments",
-
- // Don't warn about struct padding
- "-Wno-padded",
-
- // We are aware of the risks inherent in comparing floats for equality
- "-Wno-float-equal",
-
- // Pure abstract classes trigger this warning
- "-Wno-weak-vtables",
-
- // Allow four-character integer literals
- "-Wno-four-char-constants",
-
- // Allow documentation warnings
- "-Wno-documentation",
-
- // Allow implicit instantiation for templated class function
- "-Wno-undefined-func-template",
-
- // Allow explicitly marking struct as packed even when unnecessary
- "-Wno-packed",
-
+ "-Wextra",
"-DDEBUG_ONLY_CODE=0",
],
@@ -91,6 +54,7 @@
"BufferQueueConsumer.cpp",
"BufferQueueCore.cpp",
"BufferQueueProducer.cpp",
+ "BufferQueueThreadState.cpp",
"BufferSlot.cpp",
"ConsumerBase.cpp",
"CpuConsumer.cpp",
@@ -120,35 +84,48 @@
"view/Surface.cpp",
"bufferqueue/1.0/B2HProducerListener.cpp",
"bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
+ "bufferqueue/1.0/H2BProducerListener.cpp",
+ "bufferqueue/2.0/B2HGraphicBufferProducer.cpp",
+ "bufferqueue/2.0/B2HProducerListener.cpp",
+ "bufferqueue/2.0/H2BGraphicBufferProducer.cpp",
+ "bufferqueue/2.0/H2BProducerListener.cpp",
+ "bufferqueue/2.0/types.cpp",
],
shared_libs: [
"android.frameworks.bufferhub@1.0",
+ "android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
"android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hidl.token@1.0-utils",
"libbase",
- "libsync",
"libbinder",
"libbufferhub",
"libbufferhubqueue", // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
- "libpdx_default_transport",
"libcutils",
"libEGL",
"libGLESv2",
- "libui",
- "libutils",
- "libnativewindow",
- "liblog",
- "libinput",
"libhidlbase",
"libhidltransport",
- "android.hidl.token@1.0-utils",
- "android.hardware.graphics.bufferqueue@1.0",
+ "libhwbinder",
+ "libinput",
+ "liblog",
+ "libnativewindow",
+ "libpdx_default_transport",
+ "libsync",
+ "libui",
+ "libutils",
+ "libvndksupport",
],
// bufferhub is not used when building libgui for vendors
target: {
vendor: {
- cflags: ["-DNO_BUFFERHUB", "-DNO_INPUT"],
+ cflags: [
+ "-DNO_BUFFERHUB",
+ "-DNO_INPUT",
+ ],
exclude_srcs: [
"BufferHubConsumer.cpp",
"BufferHubProducer.cpp",
@@ -157,16 +134,16 @@
"android.frameworks.bufferhub@1.0",
"libbufferhub",
"libbufferhubqueue",
+ "libinput",
"libpdx_default_transport",
- "libinput"
],
},
},
header_libs: [
"libdvr_headers",
- "libnativebase_headers",
"libgui_headers",
+ "libnativebase_headers",
"libpdx_headers",
],
@@ -175,9 +152,11 @@
"libEGL",
"libnativewindow",
"libui",
- "android.hidl.token@1.0-utils",
"android.hardware.graphics.bufferqueue@1.0",
+ "android.hardware.graphics.bufferqueue@2.0",
"android.hardware.graphics.common@1.1",
+ "android.hardware.graphics.common@1.2",
+ "android.hidl.token@1.0-utils",
],
export_header_lib_headers: [
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index 3837c3e..f2d5c8e 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -34,9 +34,10 @@
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
-#include <binder/IPCThreadState.h>
+#include <private/gui/BufferQueueThreadState.h>
#ifndef __ANDROID_VNDK__
#include <binder/PermissionCache.h>
+#include <vndksupport/linker.h>
#endif
#include <system/window.h>
@@ -758,19 +759,29 @@
return savedErrno ? -savedErrno : UNKNOWN_ERROR;
}
- const IPCThreadState* ipc = IPCThreadState::self();
- const uid_t uid = ipc->getCallingUid();
+ bool denied = false;
+ const uid_t uid = BufferQueueThreadState::getCallingUid();
#ifndef __ANDROID_VNDK__
// permission check can't be done for vendors as vendors have no access to
- // the PermissionController
- const pid_t pid = ipc->getCallingPid();
- if ((uid != shellUid) &&
- !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
- outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
- "from pid=%d, uid=%d\n", pid, uid);
+ // the PermissionController. We need to do a runtime check as well, since
+ // the system variant of libgui can be loaded in a vendor process. For eg:
+ // if a HAL uses an llndk library that depends on libgui (libmediandk etc).
+ if (!android_is_in_vendor_process()) {
+ const pid_t pid = BufferQueueThreadState::getCallingPid();
+ if ((uid != shellUid) &&
+ !PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
+ outResult->appendFormat("Permission Denial: can't dump BufferQueueConsumer "
+ "from pid=%d, uid=%d\n",
+ pid, uid);
+ denied = true;
+ }
+ }
#else
if (uid != shellUid) {
+ denied = true;
+ }
#endif
+ if (denied) {
android_errorWriteWithInfoLog(0x534e4554, "27046057",
static_cast<int32_t>(uid), nullptr, 0);
return PERMISSION_DENIED;
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 5e250a4..a462b03 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -35,6 +35,7 @@
#include <gui/GLConsumer.h>
#include <gui/IConsumerListener.h>
#include <gui/IProducerListener.h>
+#include <private/gui/BufferQueueThreadState.h>
#include <utils/Log.h>
#include <utils/Trace.h>
@@ -1210,7 +1211,7 @@
status = BAD_VALUE;
break;
}
- mCore->mConnectedPid = IPCThreadState::self()->getCallingPid();
+ mCore->mConnectedPid = BufferQueueThreadState::getCallingPid();
mCore->mBufferHasBeenQueued = false;
mCore->mDequeueBufferCannotBlock = false;
if (mDequeueTimeout < 0) {
@@ -1233,7 +1234,7 @@
Mutex::Autolock lock(mCore->mMutex);
if (mode == DisconnectMode::AllLocal) {
- if (IPCThreadState::self()->getCallingPid() != mCore->mConnectedPid) {
+ if (BufferQueueThreadState::getCallingPid() != mCore->mConnectedPid) {
return NO_ERROR;
}
api = BufferQueueCore::CURRENTLY_CONNECTED_API;
diff --git a/libs/gui/BufferQueueThreadState.cpp b/libs/gui/BufferQueueThreadState.cpp
new file mode 100644
index 0000000..3b531ec
--- /dev/null
+++ b/libs/gui/BufferQueueThreadState.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/IPCThreadState.h>
+#include <hwbinder/IPCThreadState.h>
+#include <private/gui/BufferQueueThreadState.h>
+#include <unistd.h>
+
+namespace android {
+
+uid_t BufferQueueThreadState::getCallingUid() {
+ if (hardware::IPCThreadState::self()->isServingCall()) {
+ return hardware::IPCThreadState::self()->getCallingUid();
+ }
+ return IPCThreadState::self()->getCallingUid();
+}
+
+pid_t BufferQueueThreadState::getCallingPid() {
+ if (hardware::IPCThreadState::self()->isServingCall()) {
+ return hardware::IPCThreadState::self()->getCallingPid();
+ }
+ return IPCThreadState::self()->getCallingPid();
+}
+
+} // namespace android
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 8907de4..9dde15d 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -30,16 +30,21 @@
#ifndef NO_BUFFERHUB
#include <gui/BufferHubProducer.h>
#endif
+
+#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
#include <gui/BufferQueueDefs.h>
#include <gui/IGraphicBufferProducer.h>
#include <gui/IProducerListener.h>
-#include <gui/bufferqueue/1.0/H2BGraphicBufferProducer.h>
-
namespace android {
// ----------------------------------------------------------------------------
-using ::android::hardware::graphics::bufferqueue::V1_0::utils::
+using H2BGraphicBufferProducerV1_0 =
+ ::android::hardware::graphics::bufferqueue::V1_0::utils::
+ H2BGraphicBufferProducer;
+using H2BGraphicBufferProducerV2_0 =
+ ::android::hardware::graphics::bufferqueue::V2_0::utils::
H2BGraphicBufferProducer;
enum {
@@ -534,7 +539,9 @@
BpGraphicBufferProducer::~BpGraphicBufferProducer() {}
class HpGraphicBufferProducer : public HpInterface<
- BpGraphicBufferProducer, H2BGraphicBufferProducer> {
+ BpGraphicBufferProducer,
+ H2BGraphicBufferProducerV1_0,
+ H2BGraphicBufferProducerV2_0> {
public:
explicit HpGraphicBufferProducer(const sp<IBinder>& base) : PBase(base) {}
diff --git a/libs/gui/IProducerListener.cpp b/libs/gui/IProducerListener.cpp
index 62abfa8..936063a 100644
--- a/libs/gui/IProducerListener.cpp
+++ b/libs/gui/IProducerListener.cpp
@@ -15,7 +15,8 @@
*/
#include <binder/Parcel.h>
-
+#include <gui/bufferqueue/1.0/H2BProducerListener.h>
+#include <gui/bufferqueue/2.0/H2BProducerListener.h>
#include <gui/IProducerListener.h>
namespace android {
@@ -61,7 +62,24 @@
// translation unit (see clang warning -Wweak-vtables)
BpProducerListener::~BpProducerListener() {}
-IMPLEMENT_META_INTERFACE(ProducerListener, "android.gui.IProducerListener")
+class HpProducerListener : public HpInterface<
+ BpProducerListener,
+ hardware::graphics::bufferqueue::V1_0::utils::H2BProducerListener,
+ hardware::graphics::bufferqueue::V2_0::utils::H2BProducerListener> {
+public:
+ explicit HpProducerListener(const sp<IBinder>& base) : PBase{base} {}
+
+ virtual void onBufferReleased() override {
+ mBase->onBufferReleased();
+ }
+
+ virtual bool needsReleaseNotify() override {
+ return mBase->needsReleaseNotify();
+ }
+};
+
+IMPLEMENT_HYBRID_META_INTERFACE(ProducerListener,
+ "android.gui.IProducerListener")
status_t BnProducerListener::onTransact(uint32_t code, const Parcel& data,
Parcel* reply, uint32_t flags) {
diff --git a/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
new file mode 100644
index 0000000..2712f42
--- /dev/null
+++ b/libs/gui/bufferqueue/1.0/H2BProducerListener.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BProducerListener@1.0"
+
+#include <android-base/logging.h>
+
+#include <gui/bufferqueue/1.0/H2BProducerListener.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+
+H2BProducerListener::H2BProducerListener(sp<HProducerListener> const& base)
+ : CBase{base} {
+}
+
+void H2BProducerListener::onBufferReleased() {
+ if (!mBase->onBufferReleased().isOk()) {
+ LOG(ERROR) << "onBufferReleased: transaction failed.";
+ }
+}
+
+bool H2BProducerListener::needsReleaseNotify() {
+ Return<bool> transResult = mBase->needsReleaseNotify();
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "needsReleaseNotify: transaction failed.";
+ return false;
+ }
+ return static_cast<bool>(transResult);
+}
+
+} // namespace utils
+} // namespace V1_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
new file mode 100644
index 0000000..e039593
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/B2HGraphicBufferProducer.cpp
@@ -0,0 +1,331 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BGraphicBufferProducer@2.0"
+
+#include <android-base/logging.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <gui/bufferqueue/2.0/H2BProducerListener.h>
+#include <gui/bufferqueue/2.0/B2HGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// B2HGraphicBufferProducer
+// ========================
+
+B2HGraphicBufferProducer::B2HGraphicBufferProducer(
+ sp<BGraphicBufferProducer> const& base)
+ : mBase{base} {
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setMaxDequeuedBufferCount(
+ int32_t maxDequeuedBuffers) {
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->setMaxDequeuedBufferCount(
+ static_cast<int>(maxDequeuedBuffers)),
+ &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::requestBuffer(
+ int32_t slot,
+ requestBuffer_cb _hidl_cb) {
+ sp<GraphicBuffer> bBuffer;
+ HStatus hStatus{};
+ HardwareBuffer hBuffer{};
+ uint32_t hGenerationNumber{};
+ bool converted =
+ b2h(mBase->requestBuffer(
+ static_cast<int>(slot), &bBuffer),
+ &hStatus) &&
+ b2h(bBuffer, &hBuffer, &hGenerationNumber);
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ hBuffer, hGenerationNumber);
+ return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setAsyncMode(bool async) {
+ HStatus hStatus{};
+ bool converted = b2h(mBase->setAsyncMode(async), &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::dequeueBuffer(
+ DequeueBufferInput const& input,
+ dequeueBuffer_cb _hidl_cb) {
+ int bSlot{};
+ sp<BFence> bFence;
+ HStatus hStatus{};
+ DequeueBufferOutput hOutput{};
+ HFenceWrapper hFenceWrapper;
+ bool converted =
+ b2h(mBase->dequeueBuffer(
+ &bSlot,
+ &bFence,
+ input.width,
+ input.height,
+ static_cast<PixelFormat>(input.format),
+ input.usage,
+ &hOutput.bufferAge,
+ nullptr /* outTimestamps */),
+ &hStatus,
+ &hOutput.bufferNeedsReallocation,
+ &hOutput.releaseAllBuffers) &&
+ b2h(bFence, &hFenceWrapper);
+ hOutput.fence = hFenceWrapper.getHandle();
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ static_cast<int32_t>(bSlot),
+ hOutput);
+ return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::detachBuffer(int32_t slot) {
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->detachBuffer(static_cast<int>(slot)), &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::detachNextBuffer(
+ detachNextBuffer_cb _hidl_cb) {
+ sp<GraphicBuffer> bBuffer;
+ sp<BFence> bFence;
+ HStatus hStatus{};
+ HardwareBuffer hBuffer{};
+ HFenceWrapper hFenceWrapper;
+ bool converted =
+ b2h(mBase->detachNextBuffer(&bBuffer, &bFence), &hStatus) &&
+ b2h(bBuffer, &hBuffer) &&
+ b2h(bFence, &hFenceWrapper);
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ hBuffer,
+ hFenceWrapper.getHandle());
+ return {};
+}
+
+Return<void> B2HGraphicBufferProducer::attachBuffer(
+ HardwareBuffer const& hBuffer,
+ uint32_t generationNumber,
+ attachBuffer_cb _hidl_cb) {
+ sp<GraphicBuffer> bBuffer;
+ if (!h2b(hBuffer, &bBuffer) || !bBuffer) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR,
+ static_cast<int32_t>(SlotIndex::INVALID),
+ false);
+ return {};
+ }
+ bBuffer->setGenerationNumber(generationNumber);
+
+ int bSlot{};
+ HStatus hStatus{};
+ bool releaseAllBuffers{};
+ bool converted = b2h(
+ mBase->attachBuffer(&bSlot, bBuffer), &hStatus,
+ nullptr /* bufferNeedsReallocation */,
+ &releaseAllBuffers);
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ static_cast<int32_t>(bSlot),
+ releaseAllBuffers);
+ return {};
+}
+
+Return<void> B2HGraphicBufferProducer::queueBuffer(
+ int32_t slot,
+ QueueBufferInput const& hInput,
+ queueBuffer_cb _hidl_cb) {
+ using HOutput = QueueBufferOutput;
+ using BInput = BGraphicBufferProducer::QueueBufferInput;
+ using BOutput = BGraphicBufferProducer::QueueBufferOutput;
+
+ BInput bInput{
+ hInput.timestamp,
+ hInput.isAutoTimestamp,
+ static_cast<android_dataspace>(hInput.dataSpace),
+ {}, /* crop */
+ 0 /* scalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE */,
+ static_cast<uint32_t>(hInput.transform),
+ {}, /* fence */
+ static_cast<uint32_t>(hInput.stickyTransform),
+ false /* getFrameTimestamps */};
+
+ // Convert crop.
+ if (!h2b(hInput.crop, &bInput.crop)) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+ return {};
+ }
+
+ // Convert surfaceDamage.
+ if (!h2b(hInput.surfaceDamage, &bInput.surfaceDamage)) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+ return {};
+ }
+
+ // Convert fence.
+ if (!h2b(hInput.fence, &bInput.fence)) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+ return {};
+ }
+
+ BOutput bOutput{};
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->queueBuffer(static_cast<int>(slot), bInput, &bOutput),
+ &hStatus);
+
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ HOutput{bOutput.width,
+ bOutput.height,
+ static_cast<int32_t>(bOutput.transformHint),
+ bOutput.numPendingBuffers,
+ bOutput.nextFrameNumber,
+ bOutput.bufferReplaced});
+ return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::cancelBuffer(
+ int32_t slot,
+ hidl_handle const& fence) {
+ sp<BFence> bFence;
+ if (!h2b(fence.getNativeHandle(), &bFence)) {
+ return {HStatus::UNKNOWN_ERROR};
+ }
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->cancelBuffer(static_cast<int>(slot), bFence),
+ &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<void> B2HGraphicBufferProducer::query(int32_t what, query_cb _hidl_cb) {
+ int value{};
+ int result = mBase->query(static_cast<int>(what), &value);
+ _hidl_cb(static_cast<int32_t>(result), static_cast<int32_t>(value));
+ return {};
+}
+
+Return<void> B2HGraphicBufferProducer::connect(
+ sp<HProducerListener> const& hListener,
+ HConnectionType hConnectionType,
+ bool producerControlledByApp,
+ connect_cb _hidl_cb) {
+ using BOutput = BGraphicBufferProducer::QueueBufferOutput;
+ using HOutput = HGraphicBufferProducer::QueueBufferOutput;
+ sp<BProducerListener> bListener = new H2BProducerListener(hListener);
+ if (!bListener) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+ return {};
+ }
+ int bConnectionType;
+ if (!h2b(hConnectionType, &bConnectionType)) {
+ _hidl_cb(HStatus::UNKNOWN_ERROR, HOutput{});
+ return {};
+ }
+ BOutput bOutput{};
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->connect(bListener,
+ bConnectionType,
+ producerControlledByApp,
+ &bOutput),
+ &hStatus);
+ _hidl_cb(converted ? hStatus : HStatus::UNKNOWN_ERROR,
+ HOutput{bOutput.width,
+ bOutput.height,
+ static_cast<int32_t>(bOutput.transformHint),
+ bOutput.numPendingBuffers,
+ bOutput.nextFrameNumber,
+ bOutput.bufferReplaced});
+ return {};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::disconnect(
+ HConnectionType hConnectionType) {
+ int bConnectionType;
+ if (!h2b(hConnectionType, &bConnectionType)) {
+ return {HStatus::UNKNOWN_ERROR};
+ }
+ HStatus hStatus{};
+ bool converted = b2h(mBase->disconnect(bConnectionType), &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::allocateBuffers(
+ uint32_t width, uint32_t height,
+ uint32_t format, uint64_t usage) {
+ mBase->allocateBuffers(
+ width, height, static_cast<PixelFormat>(format), usage);
+ return {HStatus::OK};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::allowAllocation(bool allow) {
+ HStatus hStatus{};
+ bool converted = b2h(mBase->allowAllocation(allow), &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setGenerationNumber(
+ uint32_t generationNumber) {
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->setGenerationNumber(generationNumber),
+ &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<HStatus> B2HGraphicBufferProducer::setDequeueTimeout(
+ int64_t timeoutNs) {
+ HStatus hStatus{};
+ bool converted = b2h(
+ mBase->setDequeueTimeout(static_cast<nsecs_t>(timeoutNs)),
+ &hStatus);
+ return {converted ? hStatus : HStatus::UNKNOWN_ERROR};
+}
+
+Return<uint64_t> B2HGraphicBufferProducer::getUniqueId() {
+ uint64_t outId{};
+ HStatus hStatus{};
+ bool converted = b2h(mBase->getUniqueId(&outId), &hStatus);
+ return {converted ? outId : 0};
+}
+
+Return<void> B2HGraphicBufferProducer::getConsumerName(
+ getConsumerName_cb _hidl_cb) {
+ _hidl_cb(hidl_string{mBase->getConsumerName().c_str()});
+ return {};
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp b/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp
new file mode 100644
index 0000000..c4c96eb
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/B2HProducerListener.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gui/bufferqueue/2.0/B2HProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// B2HProducerListener
+B2HProducerListener::B2HProducerListener(sp<BProducerListener> const& base)
+ : mBase{base},
+ mNeedsReleaseNotify{base ? base->needsReleaseNotify() : false} {
+}
+
+Return<void> B2HProducerListener::onBuffersReleased(uint32_t count) {
+ if (mNeedsReleaseNotify) {
+ for (; count > 0; --count) {
+ mBase->onBufferReleased();
+ }
+ }
+ return {};
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
new file mode 100644
index 0000000..1023ef1
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/H2BGraphicBufferProducer.cpp
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BGraphicBufferProducer@2.0"
+
+#include <android-base/logging.h>
+
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <gui/bufferqueue/2.0/B2HProducerListener.h>
+#include <gui/bufferqueue/2.0/H2BGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// H2BGraphicBufferProducer
+// ========================
+
+status_t H2BGraphicBufferProducer::requestBuffer(int slot,
+ sp<GraphicBuffer>* bBuffer) {
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->requestBuffer(slot,
+ [&converted, &bStatus, bBuffer](
+ HStatus hStatus,
+ HardwareBuffer const& hBuffer,
+ uint32_t generationNumber) {
+ converted =
+ h2b(hStatus, &bStatus) &&
+ h2b(hBuffer, bBuffer);
+ if (*bBuffer) {
+ (*bBuffer)->setGenerationNumber(generationNumber);
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "requestBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "requestBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setMaxDequeuedBufferCount(
+ int maxDequeuedBuffers) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->setMaxDequeuedBufferCount(
+ static_cast<int32_t>(maxDequeuedBuffers));
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "setMaxDequeuedBufferCount: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "setMaxDequeuedBufferCount: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setAsyncMode(bool async) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->setAsyncMode(async);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "setAsyncMode: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "setAsyncMode: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::dequeueBuffer(
+ int* slot, sp<BFence>* fence,
+ uint32_t w, uint32_t h,
+ PixelFormat format, uint64_t usage,
+ uint64_t* outBufferAge, FrameEventHistoryDelta* /* outTimestamps */) {
+
+ using HInput = HGraphicBufferProducer::DequeueBufferInput;
+ HInput input{w, h, static_cast<uint32_t>(format), usage};
+
+ using HOutput = HGraphicBufferProducer::DequeueBufferOutput;
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->dequeueBuffer(input,
+ [&converted, &bStatus, slot, fence, outBufferAge] (
+ HStatus hStatus, int32_t hSlot, HOutput const& hOutput) {
+ converted = h2b(hStatus, &bStatus);
+ if (!converted || bStatus != OK) {
+ return;
+ }
+ *slot = hSlot;
+ *outBufferAge = hOutput.bufferAge;
+ bStatus =
+ (hOutput.bufferNeedsReallocation ?
+ BUFFER_NEEDS_REALLOCATION : 0) |
+ (hOutput.releaseAllBuffers ?
+ RELEASE_ALL_BUFFERS : 0);
+ converted = h2b(hOutput.fence, fence);
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "dequeueBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "dequeueBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::detachBuffer(int slot) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->detachBuffer(
+ static_cast<int32_t>(slot));
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "detachBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "detachBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::detachNextBuffer(
+ sp<GraphicBuffer>* outBuffer, sp<BFence>* outFence) {
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->detachNextBuffer(
+ [&converted, &bStatus, outBuffer, outFence] (
+ HStatus hStatus,
+ HardwareBuffer const& hBuffer,
+ hidl_handle const& hFence) {
+ converted = h2b(hStatus, &bStatus) &&
+ h2b(hBuffer, outBuffer) &&
+ h2b(hFence, outFence);
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "detachNextBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "detachNextBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::attachBuffer(
+ int* outSlot, sp<GraphicBuffer> const& buffer) {
+ HardwareBuffer hBuffer{};
+ uint32_t hGenerationNumber{};
+ if (!b2h(buffer, &hBuffer, &hGenerationNumber)) {
+ LOG(ERROR) << "attachBuffer: invalid input buffer.";
+ return BAD_VALUE;
+ }
+
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->attachBuffer(hBuffer, hGenerationNumber,
+ [&converted, &bStatus, outSlot](
+ HStatus hStatus, int32_t hSlot, bool releaseAllBuffers) {
+ converted = h2b(hStatus, &bStatus);
+ *outSlot = static_cast<int>(hSlot);
+ if (converted && releaseAllBuffers && bStatus == OK) {
+ bStatus = IGraphicBufferProducer::RELEASE_ALL_BUFFERS;
+ }
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "attachBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "attachBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::queueBuffer(
+ int slot,
+ QueueBufferInput const& input,
+ QueueBufferOutput* output) {
+ HRect hCrop{};
+ (void)b2h(input.crop, &hCrop);
+
+ using HInput = HGraphicBufferProducer::QueueBufferInput;
+ HInput hInput{
+ input.timestamp,
+ static_cast<bool>(input.isAutoTimestamp),
+ static_cast<int32_t>(input.dataSpace),
+ {}, // crop
+ static_cast<int32_t>(input.transform),
+ static_cast<int32_t>(input.stickyTransform),
+ {}, // fence
+ {} // surfaceDamage
+ };
+
+ // Convert crop.
+ if (!b2h(input.crop, &hInput.crop)) {
+ LOG(ERROR) << "queueBuffer: corrupted input crop rectangle.";
+ return UNKNOWN_ERROR;
+ }
+
+ // Convert surfaceDamage.
+ size_t numRects;
+ Rect const* rectArray = input.surfaceDamage.getArray(&numRects);
+ hInput.surfaceDamage.resize(numRects);
+ for (size_t i = 0; i < numRects; ++i) {
+ if (!b2h(rectArray[i], &hInput.surfaceDamage[i])) {
+ LOG(ERROR) << "queueBuffer: corrupted input surface damage.";
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ // Convert fence.
+ HFenceWrapper hFenceWrapper;
+ if (!b2h(input.fence, &hFenceWrapper)) {
+ LOG(ERROR) << "queueBuffer: corrupted input fence.";
+ return UNKNOWN_ERROR;
+ }
+ hInput.fence = hFenceWrapper.getHandle();
+
+ using HOutput = HGraphicBufferProducer::QueueBufferOutput;
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->queueBuffer(
+ static_cast<int32_t>(slot),
+ hInput,
+ [&converted, &bStatus, output](
+ HStatus hStatus,
+ HOutput const& hOutput) {
+ converted = h2b(hStatus, &bStatus);
+ output->width = hOutput.width;
+ output->height = hOutput.height;
+ output->transformHint =
+ static_cast<uint32_t>(hOutput.transformHint);
+ output->numPendingBuffers = hOutput.numPendingBuffers;
+ output->nextFrameNumber = hOutput.nextFrameNumber;
+ output->bufferReplaced = hOutput.bufferReplaced;
+ });
+
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "queueBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "queueBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::cancelBuffer(int slot, sp<BFence> const& fence) {
+ HFenceWrapper hFenceWrapper;
+ if (!b2h(fence, &hFenceWrapper)) {
+ LOG(ERROR) << "cancelBuffer: corrupted input fence.";
+ return UNKNOWN_ERROR;
+ }
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->cancelBuffer(
+ static_cast<int32_t>(slot),
+ hFenceWrapper.getHandle());
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "cancelBuffer: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "cancelBuffer: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+int H2BGraphicBufferProducer::query(int what, int* value) {
+ int result{};
+ Return<void> transResult = mBase->query(
+ static_cast<int32_t>(what),
+ [&result, value](int32_t r, int32_t v) {
+ result = static_cast<int>(r);
+ *value = static_cast<int>(v);
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "query: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ return result;
+}
+
+status_t H2BGraphicBufferProducer::connect(
+ sp<IProducerListener> const& listener, int api,
+ bool producerControlledByApp, QueueBufferOutput* output) {
+ HConnectionType hConnectionType;
+ if (!b2h(api, &hConnectionType)) {
+ LOG(ERROR) << "connect: corrupted input connection type.";
+ return UNKNOWN_ERROR;
+ }
+ sp<HProducerListener> hListener = nullptr;
+ if (listener && listener->needsReleaseNotify()) {
+ hListener = new B2HProducerListener(listener);
+ if (!hListener) {
+ LOG(ERROR) << "connect: failed to wrap listener.";
+ return UNKNOWN_ERROR;
+ }
+ }
+
+ using HOutput = HGraphicBufferProducer::QueueBufferOutput;
+ bool converted{};
+ status_t bStatus{};
+ Return<void> transResult = mBase->connect(
+ hListener,
+ hConnectionType,
+ producerControlledByApp,
+ [&converted, &bStatus, output](
+ HStatus hStatus,
+ HOutput hOutput) {
+ converted = h2b(hStatus, &bStatus);
+ output->width = hOutput.width;
+ output->height = hOutput.height;
+ output->transformHint =
+ static_cast<uint32_t>(hOutput.transformHint);
+ output->numPendingBuffers = hOutput.numPendingBuffers;
+ output->nextFrameNumber = hOutput.nextFrameNumber;
+ output->bufferReplaced = hOutput.bufferReplaced;
+ });
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "connect: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!converted) {
+ LOG(ERROR) << "connect: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+
+}
+
+status_t H2BGraphicBufferProducer::disconnect(int api, DisconnectMode mode) {
+ HConnectionType hConnectionType;
+ if (mode == DisconnectMode::AllLocal) {
+ hConnectionType = HConnectionType::CURRENTLY_CONNECTED;
+ } else if (!b2h(api, &hConnectionType)) {
+ LOG(ERROR) << "connect: corrupted input connection type.";
+ return UNKNOWN_ERROR;
+ }
+
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->disconnect(hConnectionType);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "disconnect: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "disconnect: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setSidebandStream(
+ sp<NativeHandle> const& stream) {
+ if (stream) {
+ LOG(INFO) << "setSidebandStream: not supported.";
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+void H2BGraphicBufferProducer::allocateBuffers(
+ uint32_t width, uint32_t height,
+ PixelFormat format, uint64_t usage) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->allocateBuffers(
+ width, height, static_cast<uint32_t>(format), usage);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "allocateBuffer: transaction failed.";
+ return;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "allocateBuffer: corrupted transaction.";
+ return;
+ }
+}
+
+status_t H2BGraphicBufferProducer::allowAllocation(bool allow) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->allowAllocation(allow);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "allowAllocation: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "allowAllocation: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::setGenerationNumber(
+ uint32_t generationNumber) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->setGenerationNumber(generationNumber);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "setGenerationNumber: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "setGenerationNumber: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+String8 H2BGraphicBufferProducer::getConsumerName() const {
+ String8 bName;
+ Return<void> transResult = mBase->getConsumerName(
+ [&bName](hidl_string const& name) {
+ bName = name.c_str();
+ });
+ return bName;
+}
+
+status_t H2BGraphicBufferProducer::setSharedBufferMode(bool sharedBufferMode) {
+ if (sharedBufferMode) {
+ LOG(INFO) << "setSharedBufferMode: not supported.";
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t H2BGraphicBufferProducer::setAutoRefresh(bool autoRefresh) {
+ if (autoRefresh) {
+ LOG(INFO) << "setAutoRefresh: not supported.";
+ return INVALID_OPERATION;
+ }
+ return OK;
+}
+
+status_t H2BGraphicBufferProducer::setDequeueTimeout(nsecs_t timeout) {
+ status_t bStatus{};
+ Return<HStatus> transResult = mBase->setDequeueTimeout(
+ static_cast<int64_t>(timeout));
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "setDequeueTimeout: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ if (!h2b(static_cast<HStatus>(transResult), &bStatus)) {
+ LOG(ERROR) << "setDequeueTimeout: corrupted transaction.";
+ return FAILED_TRANSACTION;
+ }
+ return bStatus;
+}
+
+status_t H2BGraphicBufferProducer::getLastQueuedBuffer(
+ sp<GraphicBuffer>*,
+ sp<BFence>*,
+ float[16]) {
+ LOG(INFO) << "getLastQueuedBuffer: not supported.";
+ return INVALID_OPERATION;
+}
+
+void H2BGraphicBufferProducer::getFrameTimestamps(FrameEventHistoryDelta*) {
+ LOG(INFO) << "getFrameTimestamps: not supported.";
+}
+
+status_t H2BGraphicBufferProducer::getUniqueId(uint64_t* outId) const {
+ Return<uint64_t> transResult = mBase->getUniqueId();
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "getUniqueId: transaction failed.";
+ return FAILED_TRANSACTION;
+ }
+ *outId = static_cast<uint64_t>(transResult);
+ return OK;
+}
+
+status_t H2BGraphicBufferProducer::getConsumerUsage(uint64_t*) const {
+ LOG(INFO) << "getConsumerUsage: not supported.";
+ return INVALID_OPERATION;
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
diff --git a/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
new file mode 100644
index 0000000..b81a357
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/H2BProducerListener.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "H2BProducerListener@2.0"
+
+#include <android-base/logging.h>
+
+#include <gui/bufferqueue/2.0/H2BProducerListener.h>
+#include <hidl/Status.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+
+H2BProducerListener::H2BProducerListener(sp<HProducerListener> const& base)
+ : CBase{base} {
+}
+
+void H2BProducerListener::onBufferReleased() {
+ if (mBase) {
+ Return<void> transResult = mBase->onBuffersReleased(1);
+ if (!transResult.isOk()) {
+ LOG(ERROR) << "onBuffersReleased: transaction failed.";
+ }
+ }
+}
+
+bool H2BProducerListener::needsReleaseNotify() {
+ return static_cast<bool>(mBase);
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/libs/gui/bufferqueue/2.0/types.cpp b/libs/gui/bufferqueue/2.0/types.cpp
new file mode 100644
index 0000000..a110517
--- /dev/null
+++ b/libs/gui/bufferqueue/2.0/types.cpp
@@ -0,0 +1,301 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <cutils/native_handle.h>
+#include <gui/BufferQueueCore.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <system/window.h>
+#include <vndk/hardware_buffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// Status
+// ======
+
+bool b2h(status_t from, HStatus* to,
+ bool* bufferNeedsReallocation, bool* releaseAllBuffers) {
+ switch (from) {
+ case OK:
+ *to = HStatus::OK; break;
+ case NO_MEMORY:
+ *to = HStatus::NO_MEMORY; break;
+ case NO_INIT:
+ *to = HStatus::NO_INIT; break;
+ case BAD_VALUE:
+ *to = HStatus::BAD_VALUE; break;
+ case DEAD_OBJECT:
+ *to = HStatus::DEAD_OBJECT; break;
+ case INVALID_OPERATION:
+ *to = HStatus::INVALID_OPERATION; break;
+ case TIMED_OUT:
+ *to = HStatus::TIMED_OUT; break;
+ case WOULD_BLOCK:
+ *to = HStatus::WOULD_BLOCK; break;
+ case UNKNOWN_ERROR:
+ *to = HStatus::UNKNOWN_ERROR; break;
+ default:
+ using BGBP = ::android::IGraphicBufferProducer;
+ status_t mask =
+ (bufferNeedsReallocation ? BGBP::BUFFER_NEEDS_REALLOCATION : 0)
+ | (releaseAllBuffers ? BGBP::RELEASE_ALL_BUFFERS : 0);
+ if (from & ~mask) {
+ *to = static_cast<HStatus>(from);
+ } else {
+ *to = HStatus::OK;
+ if (bufferNeedsReallocation) {
+ *bufferNeedsReallocation = from & BGBP::BUFFER_NEEDS_REALLOCATION;
+ }
+ if (releaseAllBuffers) {
+ *releaseAllBuffers = from & BGBP::RELEASE_ALL_BUFFERS;
+ }
+ }
+ }
+ return true;
+}
+
+bool h2b(HStatus from, status_t* to) {
+ switch (from) {
+ case HStatus::OK:
+ *to = OK; break;
+ case HStatus::NO_MEMORY:
+ *to = NO_MEMORY; break;
+ case HStatus::NO_INIT:
+ *to = NO_INIT; break;
+ case HStatus::BAD_VALUE:
+ *to = BAD_VALUE; break;
+ case HStatus::DEAD_OBJECT:
+ *to = DEAD_OBJECT; break;
+ case HStatus::INVALID_OPERATION:
+ *to = INVALID_OPERATION; break;
+ case HStatus::TIMED_OUT:
+ *to = TIMED_OUT; break;
+ case HStatus::WOULD_BLOCK:
+ *to = WOULD_BLOCK; break;
+ case HStatus::UNKNOWN_ERROR:
+ *to = UNKNOWN_ERROR; break;
+ default:
+ *to = static_cast<status_t>(from);
+ }
+ return true;
+}
+
+// Fence
+// =====
+
+HFenceWrapper::HFenceWrapper(native_handle_t* h) : mHandle{h} {
+}
+
+HFenceWrapper::~HFenceWrapper() {
+ native_handle_delete(mHandle);
+}
+
+HFenceWrapper& HFenceWrapper::set(native_handle_t* h) {
+ native_handle_delete(mHandle);
+ mHandle = h;
+ return *this;
+}
+
+HFenceWrapper& HFenceWrapper::operator=(native_handle_t* h) {
+ return set(h);
+}
+
+hidl_handle HFenceWrapper::getHandle() const {
+ return hidl_handle{mHandle};
+}
+
+HFenceWrapper::operator hidl_handle() const {
+ return getHandle();
+}
+
+bool b2h(sp<BFence> const& from, HFenceWrapper* to) {
+ if (!from) {
+ to->set(nullptr);
+ return true;
+ }
+ int fenceFd = from->get();
+ if (fenceFd == -1) {
+ to->set(nullptr);
+ return true;
+ }
+ native_handle_t* nh = native_handle_create(1, 0);
+ if (!nh) {
+ return false;
+ }
+ nh->data[0] = fenceFd;
+ to->set(nh);
+ return true;
+}
+
+bool h2b(native_handle_t const* from, sp<BFence>* to) {
+ if (!from || from->numFds == 0) {
+ *to = new ::android::Fence();
+ return true;
+ }
+ if (from->numFds != 1 || from->numInts != 0) {
+ return false;
+ }
+ *to = new BFence(dup(from->data[0]));
+ return true;
+}
+
+// ConnectionType
+// ==============
+
+bool b2h(int from, HConnectionType* to) {
+ *to = static_cast<HConnectionType>(from);
+ switch (from) {
+ case BufferQueueCore::CURRENTLY_CONNECTED_API:
+ *to = HConnectionType::CURRENTLY_CONNECTED; break;
+ case NATIVE_WINDOW_API_EGL:
+ *to = HConnectionType::EGL; break;
+ case NATIVE_WINDOW_API_CPU:
+ *to = HConnectionType::CPU; break;
+ case NATIVE_WINDOW_API_MEDIA:
+ *to = HConnectionType::MEDIA; break;
+ case NATIVE_WINDOW_API_CAMERA:
+ *to = HConnectionType::CAMERA; break;
+ }
+ return true;
+}
+
+bool h2b(HConnectionType from, int* to) {
+ *to = static_cast<int>(from);
+ switch (from) {
+ case HConnectionType::CURRENTLY_CONNECTED:
+ *to = BufferQueueCore::CURRENTLY_CONNECTED_API; break;
+ case HConnectionType::EGL:
+ *to = NATIVE_WINDOW_API_EGL; break;
+ case HConnectionType::CPU:
+ *to = NATIVE_WINDOW_API_CPU; break;
+ case HConnectionType::MEDIA:
+ *to = NATIVE_WINDOW_API_MEDIA; break;
+ case HConnectionType::CAMERA:
+ *to = NATIVE_WINDOW_API_CAMERA; break;
+ }
+ return true;
+}
+
+// Rect
+// ====
+
+bool b2h(BRect const& from, HRect* to) {
+ BRect* dst = reinterpret_cast<BRect*>(to->data());
+ dst->left = from.left;
+ dst->top = from.top;
+ dst->right = from.right;
+ dst->bottom = from.bottom;
+ return true;
+}
+
+bool h2b(HRect const& from, BRect* to) {
+ BRect const* src = reinterpret_cast<BRect const*>(from.data());
+ to->left = src->left;
+ to->top = src->top;
+ to->right = src->right;
+ to->bottom = src->bottom;
+ return true;
+}
+
+// Region
+// ======
+
+bool b2h(BRegion const& from, HRegion* to) {
+ size_t numRects;
+ BRect const* rectArray = from.getArray(&numRects);
+ to->resize(numRects);
+ for (size_t i = 0; i < numRects; ++i) {
+ if (!b2h(rectArray[i], &(*to)[i])) {
+ return false;
+ }
+ }
+ return true;
+}
+
+bool h2b(HRegion const& from, BRegion* to) {
+ if (from.size() > 0) {
+ BRect bRect;
+ if (!h2b(from[0], &bRect)) {
+ return false;
+ }
+ to->set(bRect);
+ for (size_t i = 1; i < from.size(); ++i) {
+ if (!h2b(from[i], &bRect)) {
+ return false;
+ }
+ to->addRectUnchecked(
+ static_cast<int>(bRect.left),
+ static_cast<int>(bRect.top),
+ static_cast<int>(bRect.right),
+ static_cast<int>(bRect.bottom));
+ }
+ } else {
+ to->clear();
+ }
+ return true;
+}
+
+// GraphicBuffer
+// =============
+
+// The handle is not cloned. Its lifetime is tied to the original GraphicBuffer.
+bool b2h(sp<GraphicBuffer> const& from, HardwareBuffer* to,
+ uint32_t* toGenerationNumber) {
+ if (!from) {
+ return false;
+ }
+ AHardwareBuffer* hwBuffer = from->toAHardwareBuffer();
+ to->nativeHandle.setTo(
+ const_cast<native_handle_t*>(
+ AHardwareBuffer_getNativeHandle(hwBuffer)),
+ false);
+ AHardwareBuffer_describe(
+ hwBuffer,
+ reinterpret_cast<AHardwareBuffer_Desc*>(to->description.data()));
+ if (toGenerationNumber) {
+ *toGenerationNumber = from->getGenerationNumber();
+ }
+ return true;
+}
+
+// The handle is cloned.
+bool h2b(HardwareBuffer const& from, sp<GraphicBuffer>* to) {
+ AHardwareBuffer_Desc const* desc =
+ reinterpret_cast<AHardwareBuffer_Desc const*>(
+ from.description.data());
+ native_handle_t const* handle = from.nativeHandle;
+ AHardwareBuffer* hwBuffer;
+ if (AHardwareBuffer_createFromHandle(
+ desc, handle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
+ &hwBuffer) != OK) {
+ return false;
+ }
+ *to = GraphicBuffer::fromAHardwareBuffer(hwBuffer);
+ return true;
+}
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 8ff8d81..2f538ad 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -35,6 +35,7 @@
#include <hidl/HybridInterface.h>
#include <android/hardware/graphics/bufferqueue/1.0/IGraphicBufferProducer.h>
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
namespace android {
// ----------------------------------------------------------------------------
@@ -42,8 +43,6 @@
class IProducerListener;
class NativeHandle;
class Surface;
-typedef ::android::hardware::graphics::bufferqueue::V1_0::IGraphicBufferProducer
- HGraphicBufferProducer;
/*
* This class defines the Binder IPC interface for the producer side of
@@ -62,7 +61,16 @@
class IGraphicBufferProducer : public IInterface
{
public:
- DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer, HGraphicBufferProducer)
+ using HGraphicBufferProducerV1_0 =
+ ::android::hardware::graphics::bufferqueue::V1_0::
+ IGraphicBufferProducer;
+ using HGraphicBufferProducerV2_0 =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IGraphicBufferProducer;
+
+ DECLARE_HYBRID_META_INTERFACE(GraphicBufferProducer,
+ HGraphicBufferProducerV1_0,
+ HGraphicBufferProducerV2_0)
enum {
// A flag returned by dequeueBuffer when the client needs to call
@@ -366,7 +374,6 @@
const HdrMetadata& getHdrMetadata() const { return hdrMetadata; }
void setHdrMetadata(const HdrMetadata& metadata) { hdrMetadata = metadata; }
- private:
int64_t timestamp{0};
int isAutoTimestamp{0};
android_dataspace dataSpace{HAL_DATASPACE_UNKNOWN};
diff --git a/libs/gui/include/gui/IProducerListener.h b/libs/gui/include/gui/IProducerListener.h
index e808bd3..a13d8e4 100644
--- a/libs/gui/include/gui/IProducerListener.h
+++ b/libs/gui/include/gui/IProducerListener.h
@@ -17,8 +17,10 @@
#ifndef ANDROID_GUI_IPRODUCERLISTENER_H
#define ANDROID_GUI_IPRODUCERLISTENER_H
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
#include <binder/IInterface.h>
-
+#include <hidl/HybridInterface.h>
#include <utils/RefBase.h>
namespace android {
@@ -47,7 +49,14 @@
class IProducerListener : public ProducerListener, public IInterface
{
public:
- DECLARE_META_INTERFACE(ProducerListener)
+ using HProducerListener1 =
+ ::android::hardware::graphics::bufferqueue::V1_0::IProducerListener;
+ using HProducerListener2 =
+ ::android::hardware::graphics::bufferqueue::V2_0::IProducerListener;
+ DECLARE_HYBRID_META_INTERFACE(
+ ProducerListener,
+ HProducerListener1,
+ HProducerListener2)
};
class BnProducerListener : public BnInterface<IProducerListener>
diff --git a/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h
new file mode 100644
index 0000000..211fdd5
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/1.0/H2BProducerListener.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H
+
+#include <android/hardware/graphics/bufferqueue/1.0/IProducerListener.h>
+#include <gui/IProducerListener.h>
+#include <hidl/HybridInterface.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V1_0 {
+namespace utils {
+
+using HProducerListener = ::android::hardware::graphics::bufferqueue::V1_0::
+ IProducerListener;
+
+using BProducerListener = ::android::IProducerListener;
+
+class H2BProducerListener
+ : public H2BConverter<HProducerListener, BnProducerListener> {
+public:
+ H2BProducerListener(sp<HProducerListener> const& base);
+ virtual void onBufferReleased() override;
+ virtual bool needsReleaseNotify() override;
+};
+
+} // namespace utils
+} // namespace V1_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V1_0_H2BPRODUCERLISTENER_H
+
diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h
new file mode 100644
index 0000000..1c58167
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/B2HGraphicBufferProducer.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/bufferqueue/2.0/types.h>
+#include <hidl/HidlSupport.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using HGraphicBufferProducer =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IGraphicBufferProducer;
+using BGraphicBufferProducer =
+ ::android::
+ IGraphicBufferProducer;
+using HProducerListener =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IProducerListener;
+
+using ::android::hardware::Return;
+using ::android::hardware::hidl_handle;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+
+using ::android::hardware::graphics::common::V1_2::HardwareBuffer;
+
+class B2HGraphicBufferProducer : public HGraphicBufferProducer {
+public:
+ B2HGraphicBufferProducer(sp<BGraphicBufferProducer> const& base);
+
+ virtual Return<HStatus> setMaxDequeuedBufferCount(
+ int32_t maxDequeuedBuffers) override;
+
+ virtual Return<void> requestBuffer(
+ int32_t slot,
+ requestBuffer_cb _hidl_cb) override;
+
+ virtual Return<HStatus> setAsyncMode(bool async) override;
+
+ virtual Return<void> dequeueBuffer(
+ DequeueBufferInput const& input,
+ dequeueBuffer_cb _hidl_cb) override;
+
+ virtual Return<HStatus> detachBuffer(int32_t slot) override;
+
+ virtual Return<void> detachNextBuffer(
+ detachNextBuffer_cb _hidl_cb) override;
+
+ virtual Return<void> attachBuffer(
+ HardwareBuffer const& buffer,
+ uint32_t generationNumber,
+ attachBuffer_cb _hidl_cb) override;
+
+ virtual Return<void> queueBuffer(
+ int32_t slot,
+ QueueBufferInput const& input,
+ queueBuffer_cb _hidl_cb) override;
+
+ virtual Return<HStatus> cancelBuffer(
+ int32_t slot,
+ hidl_handle const& fence) override;
+
+ virtual Return<void> query(int32_t what, query_cb _hidl_cb) override;
+
+ virtual Return<void> connect(
+ sp<HProducerListener> const& listener,
+ HConnectionType api,
+ bool producerControlledByApp,
+ connect_cb _hidl_cb) override;
+
+ virtual Return<HStatus> disconnect(HConnectionType api) override;
+
+ virtual Return<HStatus> allocateBuffers(
+ uint32_t width, uint32_t height,
+ uint32_t format, uint64_t usage) override;
+
+ virtual Return<HStatus> allowAllocation(bool allow) override;
+
+ virtual Return<HStatus> setGenerationNumber(uint32_t generationNumber) override;
+
+ virtual Return<HStatus> setDequeueTimeout(int64_t timeoutNs) override;
+
+ virtual Return<uint64_t> getUniqueId() override;
+
+ virtual Return<void> getConsumerName(getConsumerName_cb _hidl_cb) override;
+
+protected:
+ sp<BGraphicBufferProducer> mBase;
+};
+
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HGRAPHICBUFFERPRODUCER_H
diff --git a/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h
new file mode 100644
index 0000000..b48a473
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/B2HProducerListener.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H
+
+#include <android/hidl/base/1.0/IBase.h>
+#include <binder/IBinder.h>
+#include <gui/IProducerListener.h>
+#include <hidl/Status.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using ::android::hardware::Return;
+
+using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0::
+ IProducerListener;
+
+using BProducerListener = ::android::IProducerListener;
+
+struct B2HProducerListener : public HProducerListener {
+ explicit B2HProducerListener(sp<BProducerListener> const& base);
+ Return<void> onBuffersReleased(uint32_t count) override;
+protected:
+ sp<BProducerListener> mBase;
+ bool mNeedsReleaseNotify;
+};
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_B2HPRODUCERLISTENER_H
+
diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h b/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h
new file mode 100644
index 0000000..7dd1617
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/H2BGraphicBufferProducer.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H
+
+#include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
+#include <hidl/HybridInterface.h>
+#include <ui/Fence.h>
+
+#include <android/hardware/graphics/bufferqueue/2.0/IGraphicBufferProducer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using ::android::BnGraphicBufferProducer;
+using ::android::IProducerListener;
+using Fence = ::android::Fence;
+
+using HGraphicBufferProducer =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IGraphicBufferProducer;
+using HProducerListener =
+ ::android::hardware::graphics::bufferqueue::V2_0::
+ IProducerListener;
+using BGraphicBufferProducer =
+ ::android::IGraphicBufferProducer;
+
+struct H2BGraphicBufferProducer
+ : public ::android::H2BConverter<HGraphicBufferProducer,
+ BnGraphicBufferProducer> {
+ explicit H2BGraphicBufferProducer(
+ sp<HGraphicBufferProducer> const& base) : CBase(base) {}
+
+ virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) override;
+ virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) override;
+ virtual status_t setAsyncMode(bool async) override;
+ virtual status_t dequeueBuffer(
+ int* slot, sp<Fence>* fence,
+ uint32_t width, uint32_t height,
+ PixelFormat format, uint64_t usage,
+ uint64_t* outBufferAge,
+ FrameEventHistoryDelta* outTimestamps) override;
+ virtual status_t detachBuffer(int slot) override;
+ virtual status_t detachNextBuffer(
+ sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence) override;
+ virtual status_t attachBuffer(
+ int* outSlot,
+ sp<GraphicBuffer> const& buffer) override;
+ virtual status_t queueBuffer(
+ int slot,
+ QueueBufferInput const& input,
+ QueueBufferOutput* output) override;
+ virtual status_t cancelBuffer(int slot, sp<Fence> const& fence) override;
+ virtual int query(int what, int* value) override;
+ virtual status_t connect(
+ sp<IProducerListener> const& listener,
+ int api,
+ bool producerControlledByApp,
+ QueueBufferOutput* output) override;
+ virtual status_t disconnect(
+ int api,
+ DisconnectMode mode = DisconnectMode::Api) override;
+ virtual status_t setSidebandStream(sp<NativeHandle> const& stream) override;
+ virtual void allocateBuffers(
+ uint32_t width, uint32_t height,
+ PixelFormat format, uint64_t usage) override;
+ virtual status_t allowAllocation(bool allow) override;
+ virtual status_t setGenerationNumber(uint32_t generationNumber) override;
+ virtual String8 getConsumerName() const override;
+ virtual status_t setSharedBufferMode(bool sharedBufferMode) override;
+ virtual status_t setAutoRefresh(bool autoRefresh) override;
+ virtual status_t setDequeueTimeout(nsecs_t timeout) override;
+ virtual status_t getLastQueuedBuffer(sp<GraphicBuffer>* outBuffer,
+ sp<Fence>* outFence, float outTransformMatrix[16]) override;
+ virtual void getFrameTimestamps(FrameEventHistoryDelta* outDelta) override;
+ virtual status_t getUniqueId(uint64_t* outId) const override;
+ virtual status_t getConsumerUsage(uint64_t* outUsage) const override;
+};
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BGRAPHICBUFFERPRODUCER_H
diff --git a/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h
new file mode 100644
index 0000000..898920b
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/H2BProducerListener.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/IProducerListener.h>
+#include <gui/IProducerListener.h>
+#include <hidl/HybridInterface.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+using HProducerListener = ::android::hardware::graphics::bufferqueue::V2_0::
+ IProducerListener;
+
+using BProducerListener = ::android::IProducerListener;
+
+class H2BProducerListener
+ : public H2BConverter<HProducerListener, BnProducerListener> {
+public:
+ H2BProducerListener(sp<HProducerListener> const& base);
+ virtual void onBufferReleased() override;
+ virtual bool needsReleaseNotify() override;
+};
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_H2BPRODUCERLISTENER_H
+
diff --git a/libs/gui/include/gui/bufferqueue/2.0/types.h b/libs/gui/include/gui/bufferqueue/2.0/types.h
new file mode 100644
index 0000000..62176ce
--- /dev/null
+++ b/libs/gui/include/gui/bufferqueue/2.0/types.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H
+#define ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H
+
+#include <android/hardware/graphics/bufferqueue/2.0/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
+#include <hidl/HidlSupport.h>
+#include <ui/Fence.h>
+#include <ui/GraphicBuffer.h>
+
+namespace android {
+namespace hardware {
+namespace graphics {
+namespace bufferqueue {
+namespace V2_0 {
+namespace utils {
+
+// Status
+// ======
+
+using HStatus = ::android::hardware::graphics::bufferqueue::V2_0::
+ Status;
+
+// A status_t value may have flags encoded. These flags are decoded into boolean
+// values if their corresponding output pointers are not null.
+bool b2h(status_t from, HStatus* to,
+ bool* bufferNeedsReallocation = nullptr,
+ bool* releaseAllBuffers = nullptr);
+// Simple 1-to-1 mapping. If BUFFER_NEEDS_REALLOCATION or RELEASE_ALL_BUFFERS
+// needs to be added, it must be done manually afterwards.
+bool h2b(HStatus from, status_t* to);
+
+// Fence
+// =====
+
+using BFence = ::android::Fence;
+// This class manages the lifetime of a copied handle. Its destructor calls
+// native_handle_delete() but not native_handle_close().
+struct HFenceWrapper {
+ HFenceWrapper() = default;
+ // Sets mHandle to a new value.
+ HFenceWrapper(native_handle_t* h);
+ // Deletes mHandle without closing.
+ ~HFenceWrapper();
+ // Deletes mHandle without closing, then sets mHandle to a new value.
+ HFenceWrapper& set(native_handle_t* h);
+ HFenceWrapper& operator=(native_handle_t* h);
+ // Returns a non-owning hidl_handle pointing to mHandle.
+ hidl_handle getHandle() const;
+ operator hidl_handle() const;
+protected:
+ native_handle_t* mHandle{nullptr};
+};
+
+// Does not clone the fd---only copy the fd. The returned HFenceWrapper should
+// not outlive the input Fence object.
+bool b2h(sp<BFence> const& from, HFenceWrapper* to);
+// Clones the fd and puts it in a new Fence object.
+bool h2b(native_handle_t const* from, sp<BFence>* to);
+
+// ConnectionType
+// ==============
+
+using HConnectionType = ::android::hardware::graphics::bufferqueue::V2_0::
+ ConnectionType;
+
+bool b2h(int from, HConnectionType* to);
+bool h2b(HConnectionType from, int* to);
+
+// Rect
+// ====
+
+using BRect = ::android::Rect;
+using HRect = ::android::hardware::graphics::common::V1_2::Rect;
+
+bool b2h(BRect const& from, HRect* to);
+bool h2b(HRect const& from, BRect* to);
+
+// Region
+// ======
+
+using BRegion = ::android::Region;
+using HRegion = ::android::hardware::hidl_vec<HRect>;
+
+bool b2h(BRegion const& from, HRegion* to);
+bool h2b(HRegion const& from, BRegion* to);
+
+// GraphicBuffer
+// =============
+
+using HardwareBuffer = ::android::hardware::graphics::common::V1_2::
+ HardwareBuffer;
+using HardwareBufferDescription = ::android::hardware::graphics::common::V1_2::
+ HardwareBufferDescription;
+
+// Does not clone the handle. The returned HardwareBuffer should not outlive the
+// input GraphicBuffer. Note that HardwareBuffer does not carry the generation
+// number, so this function needs another output argument.
+bool b2h(sp<GraphicBuffer> const& from, HardwareBuffer* to,
+ uint32_t* toGenerationNumber = nullptr);
+// Clones the handle and creates a new GraphicBuffer from the cloned handle.
+// Note that the generation number of the GraphicBuffer has to be set manually
+// afterwards because HardwareBuffer does not have such information.
+bool h2b(HardwareBuffer const& from, sp<GraphicBuffer>* to);
+
+} // namespace utils
+} // namespace V2_0
+} // namespace bufferqueue
+} // namespace graphics
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_GRAPHICS_BUFFERQUEUE_V2_0_TYPES_H
+
diff --git a/libs/gui/include/private/gui/BufferQueueThreadState.h b/libs/gui/include/private/gui/BufferQueueThreadState.h
new file mode 100644
index 0000000..67dcf62
--- /dev/null
+++ b/libs/gui/include/private/gui/BufferQueueThreadState.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+namespace android {
+
+// TODO: Replace this with b/127962003
+class BufferQueueThreadState {
+public:
+ static pid_t getCallingPid();
+ static uid_t getCallingUid();
+};
+
+} // namespace android
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index 994e953..52fc9d5 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -636,11 +636,11 @@
}
const GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(const AHardwareBuffer* buffer) {
- return reinterpret_cast<const GraphicBuffer*>(buffer);
+ return GraphicBuffer::fromAHardwareBuffer(buffer);
}
GraphicBuffer* AHardwareBuffer_to_GraphicBuffer(AHardwareBuffer* buffer) {
- return reinterpret_cast<GraphicBuffer*>(buffer);
+ return GraphicBuffer::fromAHardwareBuffer(buffer);
}
const ANativeWindowBuffer* AHardwareBuffer_to_ANativeWindowBuffer(const AHardwareBuffer* buffer) {
@@ -652,7 +652,7 @@
}
AHardwareBuffer* AHardwareBuffer_from_GraphicBuffer(GraphicBuffer* buffer) {
- return reinterpret_cast<AHardwareBuffer*>(buffer);
+ return buffer->toAHardwareBuffer();
}
} // namespace android
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index d847884..27ab482 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -24,7 +24,7 @@
cc_library_headers {
name: "libnativewindow_headers",
export_include_dirs: ["include"],
- vendor_available: false,
+ vendor_available: true,
}
ndk_library {
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 4ca1781..e521b61 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -124,7 +124,6 @@
exclude_header_libs: [
"libbufferhub_headers",
"libdvr_headers",
- "libnativewindow_headers",
],
exclude_shared_libs: [
"android.frameworks.bufferhub@1.0",
@@ -152,6 +151,7 @@
export_header_lib_headers: [
"libbase_headers",
"libnativebase_headers",
+ "libnativewindow_headers",
"libhardware_headers",
"libui_headers",
],
diff --git a/libs/ui/ColorSpace.cpp b/libs/ui/ColorSpace.cpp
index 5b4bf23..7a14af1 100644
--- a/libs/ui/ColorSpace.cpp
+++ b/libs/ui/ColorSpace.cpp
@@ -351,13 +351,12 @@
};
}
-std::unique_ptr<float3> ColorSpace::createLUT(uint32_t size,
- const ColorSpace& src, const ColorSpace& dst) {
-
+std::unique_ptr<float3[]> ColorSpace::createLUT(uint32_t size, const ColorSpace& src,
+ const ColorSpace& dst) {
size = clamp(size, 2u, 256u);
float m = 1.0f / float(size - 1);
- std::unique_ptr<float3> lut(new float3[size * size * size]);
+ std::unique_ptr<float3[]> lut(new float3[size * size * size]);
float3* data = lut.get();
ColorSpaceConnector connector(src, dst);
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 79958ec..f800627 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -49,6 +49,22 @@
return static_cast<GraphicBuffer *>(anwb);
}
+GraphicBuffer* GraphicBuffer::fromAHardwareBuffer(AHardwareBuffer* buffer) {
+ return reinterpret_cast<GraphicBuffer*>(buffer);
+}
+
+GraphicBuffer const* GraphicBuffer::fromAHardwareBuffer(AHardwareBuffer const* buffer) {
+ return reinterpret_cast<GraphicBuffer const*>(buffer);
+}
+
+AHardwareBuffer* GraphicBuffer::toAHardwareBuffer() {
+ return reinterpret_cast<AHardwareBuffer*>(this);
+}
+
+AHardwareBuffer const* GraphicBuffer::toAHardwareBuffer() const {
+ return reinterpret_cast<AHardwareBuffer const*>(this);
+}
+
GraphicBuffer::GraphicBuffer()
: BASE(), mOwner(ownData), mBufferMapper(GraphicBufferMapper::get()),
mInitCheck(NO_ERROR), mId(getUniqueId()), mGenerationNumber(0)
diff --git a/libs/ui/include/ui/ColorSpace.h b/libs/ui/include/ui/ColorSpace.h
index 8ccf6d3..241ec10 100644
--- a/libs/ui/include/ui/ColorSpace.h
+++ b/libs/ui/include/ui/ColorSpace.h
@@ -250,8 +250,8 @@
// axis is thus already flipped
// The source color space must define its values in the domain [0..1]
// The generated LUT transforms from gamma space to gamma space
- static std::unique_ptr<float3> createLUT(uint32_t size,
- const ColorSpace& src, const ColorSpace& dst);
+ static std::unique_ptr<float3[]> createLUT(uint32_t size, const ColorSpace& src,
+ const ColorSpace& dst);
private:
static constexpr mat3 computeXYZMatrix(
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
index ec67fa9..6efecd3 100644
--- a/libs/ui/include/ui/Fence.h
+++ b/libs/ui/include/ui/Fence.h
@@ -99,6 +99,12 @@
// be returned and errno will indicate the problem.
int dup() const;
+ // Return the underlying file descriptor without giving up ownership. The
+ // returned file descriptor is only valid for as long as the owning Fence
+ // object lives. (If the situation is unclear, dup() is always a safer
+ // option.)
+ int get() const { return mFenceFd.get(); }
+
// getSignalTime returns the system monotonic clock time at which the
// fence transitioned to the signaled state. If the fence is not signaled
// then SIGNAL_TIME_PENDING is returned. If the fence is invalid or if an
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index 4d4ee68..e0c6558 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -22,6 +22,7 @@
#include <string>
+#include <android/hardware_buffer.h>
#include <ui/ANativeObjectBase.h>
#include <ui/PixelFormat.h>
#include <ui/Rect.h>
@@ -78,6 +79,10 @@
static sp<GraphicBuffer> from(ANativeWindowBuffer *);
+ static GraphicBuffer* fromAHardwareBuffer(AHardwareBuffer*);
+ static GraphicBuffer const* fromAHardwareBuffer(AHardwareBuffer const*);
+ AHardwareBuffer* toAHardwareBuffer();
+ AHardwareBuffer const* toAHardwareBuffer() const;
// Create a GraphicBuffer to be unflatten'ed into or be reallocated.
GraphicBuffer();
diff --git a/services/inputflinger/TouchVideoDevice.cpp b/services/inputflinger/TouchVideoDevice.cpp
index 76df3a1..19c1313 100644
--- a/services/inputflinger/TouchVideoDevice.cpp
+++ b/services/inputflinger/TouchVideoDevice.cpp
@@ -68,6 +68,7 @@
std::string name = reinterpret_cast<const char*>(cap.card);
struct v4l2_input v4l2_input_struct;
+ v4l2_input_struct.index = 0;
result = ioctl(fd.get(), VIDIOC_ENUMINPUT, &v4l2_input_struct);
if (result == -1) {
ALOGE("VIDIOC_ENUMINPUT failed: %s", strerror(errno));
@@ -91,10 +92,11 @@
const uint32_t width = v4l2_fmt.fmt.pix.width;
ALOGI("Frame dimensions: height = %" PRIu32 " width = %" PRIu32, height, width);
- struct v4l2_requestbuffers req;
+ struct v4l2_requestbuffers req = {};
req.count = NUM_BUFFERS;
req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
req.memory = V4L2_MEMORY_MMAP;
+ // req.reserved is zeroed during initialization, which is required per v4l docs
result = ioctl(fd.get(), VIDIOC_REQBUFS, &req);
if (result == -1) {
ALOGE("VIDIOC_REQBUFS failed: %s", strerror(errno));
@@ -108,6 +110,7 @@
struct v4l2_buffer buf = {};
buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf.memory = V4L2_MEMORY_MMAP;
+ // buf.reserved and buf.reserved2 are zeroed during initialization, required per v4l docs
std::array<const int16_t*, NUM_BUFFERS> readLocations;
for (size_t i = 0; i < NUM_BUFFERS; i++) {
buf.index = i;
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 4751e5f..1b2b180 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -304,7 +304,9 @@
setCompositionType(displayDevice, Hwc2::IComposerClient::Composition::DEVICE);
}
- ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+ ui::Dataspace dataspace = isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN
+ ? targetDataspace
+ : mCurrentDataSpace;
error = hwcLayer->setDataspace(dataspace);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 3364399..fcc2d97 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -114,7 +114,9 @@
setCompositionType(display, Hwc2::IComposerClient::Composition::SOLID_COLOR);
- const ui::Dataspace dataspace = isColorSpaceAgnostic() ? targetDataspace : mCurrentDataSpace;
+ const ui::Dataspace dataspace =
+ isColorSpaceAgnostic() && targetDataspace != ui::Dataspace::UNKNOWN ? targetDataspace
+ : mCurrentDataSpace;
error = hwcLayer->setDataspace(dataspace);
if (error != HWC2::Error::None) {
ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), dataspace,
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 379ad87..5ce72b0 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -282,8 +282,7 @@
* computation so it's enough to just omit it in the composition.
* See comment in BufferLayer::prepareClientLayer with ref to b/36727915 for why.
*/
- transform =
- ui::Transform(invTransform) * displayTransform * layerTransform * bufferTransform;
+ transform = ui::Transform(invTransform) * displayTransform * bufferTransform;
}
// this gives us only the "orientation" component of the transform
diff --git a/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h b/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h
deleted file mode 100644
index 6741cc9..0000000
--- a/services/surfaceflinger/CompositionEngine/tests/FloatRectMatcher.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <string>
-
-#include <android-base/stringprintf.h>
-#include <gmock/gmock.h>
-
-namespace {
-
-using android::base::StringAppendF;
-using FloatRect = android::FloatRect;
-
-void dumpFloatRect(const FloatRect& rect, std::string& result, const char* name) {
- StringAppendF(&result, "%s (%f %f %f %f) ", name, rect.left, rect.top, rect.right, rect.bottom);
-}
-
-// Checks for a region match
-MATCHER_P(FloatRectEq, expected, "") {
- std::string buf;
- buf.append("FloatRects are not equal\n");
- dumpFloatRect(expected, buf, "expected rect");
- dumpFloatRect(arg, buf, "actual rect");
- *result_listener << buf;
-
- const float TOLERANCE = 1e-3f;
- return (std::fabs(expected.left - arg.left) < TOLERANCE) &&
- (std::fabs(expected.top - arg.top) < TOLERANCE) &&
- (std::fabs(expected.right - arg.right) < TOLERANCE) &&
- (std::fabs(expected.bottom - arg.bottom) < TOLERANCE);
-}
-
-} // namespace
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 2504fa6..2060c5a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -21,7 +21,6 @@
#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
-#include "FloatRectMatcher.h"
#include "MockHWC2.h"
#include "MockHWComposer.h"
#include "RectMatcher.h"
@@ -107,114 +106,6 @@
}
/*
- * OutputLayer::calculateOutputSourceCrop()
- */
-
-struct OutputLayerSourceCropTest : public OutputLayerTest {
- OutputLayerSourceCropTest() {
- // Set reasonable default values for a simple case. Each test will
- // set one specific value to something different.
- mLayerState.frontEnd.geomUsesSourceCrop = true;
- mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 1920, 1080};
- mLayerState.frontEnd.geomActiveTransparentRegion = Region{};
- mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 1920.f, 1080.f};
- mLayerState.frontEnd.geomLayerTransform = ui::Transform{TR_IDENT};
- mLayerState.frontEnd.geomBufferSize = Rect{0, 0, 1920, 1080};
- mLayerState.frontEnd.geomBufferTransform = TR_IDENT;
-
- mOutputState.viewport = Rect{0, 0, 1920, 1080};
- }
-
- FloatRect calculateOutputSourceCrop() {
- mLayerState.frontEnd.geomInverseLayerTransform =
- mLayerState.frontEnd.geomLayerTransform.inverse();
-
- return mOutputLayer.calculateOutputSourceCrop();
- }
-};
-
-TEST_F(OutputLayerSourceCropTest, computesEmptyIfSourceCropNotUsed) {
- mLayerState.frontEnd.geomUsesSourceCrop = false;
-
- const FloatRect expected{};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-TEST_F(OutputLayerSourceCropTest, correctForSimpleDefaultCase) {
- const FloatRect expected{0.f, 0.f, 1920.f, 1080.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewport) {
- mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f};
-
- const FloatRect expected{0.f, 0.f, 1920.f, 1080.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-TEST_F(OutputLayerSourceCropTest, handlesBoundsOutsideViewportRotated) {
- mLayerState.frontEnd.geomLayerBounds = FloatRect{-2000.f, -2000.f, 2000.f, 2000.f};
- mLayerState.frontEnd.geomLayerTransform.set(HAL_TRANSFORM_ROT_90, 1920, 1080);
-
- const FloatRect expected{0.f, 0.f, 1080.f, 1080.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-TEST_F(OutputLayerSourceCropTest, calculateOutputSourceCropWorksWithATransformedBuffer) {
- struct Entry {
- uint32_t bufferInvDisplay;
- uint32_t buffer;
- uint32_t display;
- FloatRect expected;
- };
- // Not an exhaustive list of cases, but hopefully enough.
- const std::array<Entry, 12> testData = {
- // clang-format off
- // inv buffer display expected
- /* 0 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 1 */ Entry{false, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 2 */ Entry{false, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 3 */ Entry{false, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
-
- /* 4 */ Entry{true, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 5 */ Entry{true, TR_IDENT, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 6 */ Entry{true, TR_IDENT, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 7 */ Entry{true, TR_IDENT, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
-
- /* 8 */ Entry{false, TR_IDENT, TR_IDENT, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 9 */ Entry{false, TR_ROT_90, TR_ROT_90, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 10 */ Entry{false, TR_ROT_180, TR_ROT_180, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
- /* 11 */ Entry{false, TR_ROT_270, TR_ROT_270, FloatRect{0.f, 0.f, 1920.f, 1080.f}},
-
- // clang-format on
- };
-
- for (size_t i = 0; i < testData.size(); i++) {
- const auto& entry = testData[i];
-
- mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay;
- mLayerState.frontEnd.geomBufferTransform = entry.buffer;
- mOutputState.orientation = entry.display;
-
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(entry.expected)) << "entry " << i;
- }
-}
-
-TEST_F(OutputLayerSourceCropTest, geomContentCropAffectsCrop) {
- mLayerState.frontEnd.geomContentCrop = Rect{0, 0, 960, 540};
-
- const FloatRect expected{0.f, 0.f, 960.f, 540.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-TEST_F(OutputLayerSourceCropTest, viewportAffectsCrop) {
- mOutputState.viewport = Rect{0, 0, 960, 540};
-
- const FloatRect expected{0.f, 0.f, 960.f, 540.f};
- EXPECT_THAT(calculateOutputSourceCrop(), FloatRectEq(expected));
-}
-
-/*
* OutputLayer::calculateOutputDisplayFrame()
*/
@@ -272,7 +163,7 @@
EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
}
-TEST_F(OutputLayerDisplayFrameTest, geomLayerBoundsAffectsFrame) {
+TEST_F(OutputLayerDisplayFrameTest, geomLayerSnapToBoundsAffectsFrame) {
mLayerState.frontEnd.geomLayerBounds = FloatRect{0.f, 0.f, 960.f, 540.f};
const Rect expected{0, 0, 960, 540};
EXPECT_THAT(calculateOutputDisplayFrame(), RectEq(expected));
@@ -351,159 +242,6 @@
}
}
-TEST_F(OutputLayerTest,
- calculateOutputRelativeBufferTransformTestWithOfBufferUsesDisplayInverseTransform) {
- mLayerState.frontEnd.geomBufferUsesDisplayInverseTransform = true;
-
- struct Entry {
- uint32_t layer;
- uint32_t buffer;
- uint32_t display;
- uint32_t expected;
- };
- // Not an exhaustive list of cases, but hopefully enough.
- const std::array<Entry, 24> testData = {
- // clang-format off
- // layer buffer display expected
- /* 0 */ Entry{TR_IDENT, TR_IDENT, TR_IDENT, TR_IDENT},
- /* 1 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_90, TR_IDENT},
- /* 2 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_180, TR_IDENT},
- /* 3 */ Entry{TR_IDENT, TR_IDENT, TR_ROT_270, TR_IDENT},
-
- /* 4 */ Entry{TR_IDENT, TR_FLP_H, TR_IDENT, TR_FLP_H},
- /* 5 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_90, TR_FLP_H},
- /* 6 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_180, TR_FLP_H},
- /* 7 */ Entry{TR_IDENT, TR_FLP_H, TR_ROT_270, TR_FLP_H},
-
- /* 8 */ Entry{TR_IDENT, TR_FLP_V, TR_IDENT, TR_FLP_V},
- /* 9 */ Entry{TR_IDENT, TR_ROT_90, TR_ROT_90, TR_ROT_90},
- /* 10 */ Entry{TR_IDENT, TR_ROT_180, TR_ROT_180, TR_ROT_180},
- /* 11 */ Entry{TR_IDENT, TR_ROT_270, TR_ROT_270, TR_ROT_270},
-
- /* 12 */ Entry{TR_ROT_90, TR_IDENT, TR_IDENT, TR_IDENT ^ TR_ROT_90},
- /* 13 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_90, TR_FLP_H ^ TR_ROT_90},
- /* 14 */ Entry{TR_ROT_90, TR_IDENT, TR_ROT_180, TR_IDENT ^ TR_ROT_90},
- /* 15 */ Entry{TR_ROT_90, TR_FLP_H, TR_ROT_270, TR_FLP_H ^ TR_ROT_90},
-
- /* 16 */ Entry{TR_ROT_180, TR_FLP_H, TR_IDENT, TR_FLP_H ^ TR_ROT_180},
- /* 17 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_90, TR_IDENT ^ TR_ROT_180},
- /* 18 */ Entry{TR_ROT_180, TR_FLP_H, TR_ROT_180, TR_FLP_H ^ TR_ROT_180},
- /* 19 */ Entry{TR_ROT_180, TR_IDENT, TR_ROT_270, TR_IDENT ^ TR_ROT_180},
-
- /* 20 */ Entry{TR_ROT_270, TR_IDENT, TR_IDENT, TR_IDENT ^ TR_ROT_270},
- /* 21 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_90, TR_FLP_H ^ TR_ROT_270},
- /* 22 */ Entry{TR_ROT_270, TR_FLP_H, TR_ROT_180, TR_FLP_H ^ TR_ROT_270},
- /* 23 */ Entry{TR_ROT_270, TR_IDENT, TR_ROT_270, TR_IDENT ^ TR_ROT_270},
- // clang-format on
- };
-
- for (size_t i = 0; i < testData.size(); i++) {
- const auto& entry = testData[i];
-
- mLayerState.frontEnd.geomLayerTransform = ui::Transform{entry.layer};
- mLayerState.frontEnd.geomBufferTransform = entry.buffer;
- mOutputState.orientation = entry.display;
-
- auto actual = mOutputLayer.calculateOutputRelativeBufferTransform();
- EXPECT_EQ(entry.expected, actual) << "entry " << i;
- }
-}
-
-/*
- * OutputLayer::updateCompositionState()
- */
-
-struct OutputLayerPartialMockForUpdateCompositionState : public impl::OutputLayer {
- OutputLayerPartialMockForUpdateCompositionState(const compositionengine::Output& output,
- std::shared_ptr<compositionengine::Layer> layer,
- sp<compositionengine::LayerFE> layerFE)
- : impl::OutputLayer(output, layer, layerFE) {}
- // Mock everything called by updateCompositionState to simplify testing it.
- MOCK_CONST_METHOD0(calculateOutputSourceCrop, FloatRect());
- MOCK_CONST_METHOD0(calculateOutputDisplayFrame, Rect());
- MOCK_CONST_METHOD0(calculateOutputRelativeBufferTransform, uint32_t());
-};
-
-struct OutputLayerUpdateCompositionStateTest : public OutputLayerTest {
-public:
- OutputLayerUpdateCompositionStateTest() {
- EXPECT_CALL(*mLayer, getState()).WillRepeatedly(ReturnRef(mLayerState));
- EXPECT_CALL(mOutput, getState()).WillRepeatedly(ReturnRef(mOutputState));
- }
-
- ~OutputLayerUpdateCompositionStateTest() = default;
-
- void setupGeometryChildCallValues() {
- EXPECT_CALL(mOutputLayer, calculateOutputSourceCrop()).WillOnce(Return(kSourceCrop));
- EXPECT_CALL(mOutputLayer, calculateOutputDisplayFrame()).WillOnce(Return(kDisplayFrame));
- EXPECT_CALL(mOutputLayer, calculateOutputRelativeBufferTransform())
- .WillOnce(Return(mBufferTransform));
- }
-
- void validateComputedGeometryState() {
- const auto& state = mOutputLayer.getState();
- EXPECT_EQ(kSourceCrop, state.sourceCrop);
- EXPECT_EQ(kDisplayFrame, state.displayFrame);
- EXPECT_EQ(static_cast<Hwc2::Transform>(mBufferTransform), state.bufferTransform);
- }
-
- const FloatRect kSourceCrop{1.f, 2.f, 3.f, 4.f};
- const Rect kDisplayFrame{11, 12, 13, 14};
- uint32_t mBufferTransform{21};
-
- using OutputLayer = OutputLayerPartialMockForUpdateCompositionState;
- StrictMock<OutputLayer> mOutputLayer{mOutput, mLayer, mLayerFE};
-};
-
-TEST_F(OutputLayerUpdateCompositionStateTest, setsStateNormally) {
- mLayerState.frontEnd.isSecure = true;
- mOutputState.isSecure = true;
-
- setupGeometryChildCallValues();
-
- mOutputLayer.updateCompositionState(true);
-
- validateComputedGeometryState();
-
- EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
-}
-
-TEST_F(OutputLayerUpdateCompositionStateTest,
- alsoSetsForceCompositionIfSecureLayerOnNonsecureOutput) {
- mLayerState.frontEnd.isSecure = true;
- mOutputState.isSecure = false;
-
- setupGeometryChildCallValues();
-
- mOutputLayer.updateCompositionState(true);
-
- validateComputedGeometryState();
-
- EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
-}
-
-TEST_F(OutputLayerUpdateCompositionStateTest,
- alsoSetsForceCompositionIfUnsupportedBufferTransform) {
- mLayerState.frontEnd.isSecure = true;
- mOutputState.isSecure = true;
-
- mBufferTransform = ui::Transform::ROT_INVALID;
-
- setupGeometryChildCallValues();
-
- mOutputLayer.updateCompositionState(true);
-
- validateComputedGeometryState();
-
- EXPECT_EQ(true, mOutputLayer.getState().forceClientComposition);
-}
-
-TEST_F(OutputLayerUpdateCompositionStateTest, doesNotRecomputeGeometryIfNotRequested) {
- mOutputLayer.updateCompositionState(false);
-
- EXPECT_EQ(false, mOutputLayer.getState().forceClientComposition);
-}
-
/*
* OutputLayer::writeStateToHWC()
*/
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 16e69b9..07fe03e 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -278,14 +278,12 @@
return reduce(mBounds, activeTransparentRegion);
}
-ui::Transform Layer::getTransformWithScale() const {
+ui::Transform Layer::getBufferScaleTransform() const {
// If the layer is not using NATIVE_WINDOW_SCALING_MODE_FREEZE (e.g.
// it isFixedSize) then there may be additional scaling not accounted
- // for in the transform. We need to mirror this scaling to child surfaces
- // or we will break the contract where WM can treat child surfaces as
- // pixels in the parent surface.
+ // for in the layer transform.
if (!isFixedSize() || !mActiveBuffer) {
- return mEffectiveTransform;
+ return {};
}
// If the layer is a buffer state layer, the active width and height
@@ -293,24 +291,40 @@
const uint32_t activeWidth = getActiveWidth(getDrawingState());
const uint32_t activeHeight = getActiveHeight(getDrawingState());
if (activeWidth >= UINT32_MAX && activeHeight >= UINT32_MAX) {
- return mEffectiveTransform;
+ return {};
}
- int bufferWidth;
- int bufferHeight;
- if ((mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
- bufferWidth = mActiveBuffer->getWidth();
- bufferHeight = mActiveBuffer->getHeight();
- } else {
- bufferHeight = mActiveBuffer->getWidth();
- bufferWidth = mActiveBuffer->getHeight();
+ int bufferWidth = mActiveBuffer->getWidth();
+ int bufferHeight = mActiveBuffer->getHeight();
+
+ if (mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
+ std::swap(bufferWidth, bufferHeight);
}
+
float sx = activeWidth / static_cast<float>(bufferWidth);
float sy = activeHeight / static_cast<float>(bufferHeight);
ui::Transform extraParentScaling;
extraParentScaling.set(sx, 0, 0, sy);
- return mEffectiveTransform * extraParentScaling;
+ return extraParentScaling;
+}
+
+ui::Transform Layer::getTransformWithScale(const ui::Transform& bufferScaleTransform) const {
+ // We need to mirror this scaling to child surfaces or we will break the contract where WM can
+ // treat child surfaces as pixels in the parent surface.
+ if (!isFixedSize() || !mActiveBuffer) {
+ return mEffectiveTransform;
+ }
+ return mEffectiveTransform * bufferScaleTransform;
+}
+
+FloatRect Layer::getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const {
+ // We need the pre scaled layer bounds when computing child bounds to make sure the child is
+ // cropped to its parent layer after any buffer transform scaling is applied.
+ if (!isFixedSize() || !mActiveBuffer) {
+ return mBounds;
+ }
+ return bufferScaleTransform.inverse().transform(mBounds);
}
void Layer::computeBounds(FloatRect parentBounds, ui::Transform parentTransform) {
@@ -322,7 +336,7 @@
// Transform parent bounds to layer space
parentBounds = getActiveTransform(s).inverse().transform(parentBounds);
- // Calculate display frame
+ // Calculate source bounds
mSourceBounds = computeSourceBounds(parentBounds);
// Calculate bounds by croping diplay frame with layer crop and parent bounds
@@ -335,8 +349,12 @@
mBounds = bounds;
mScreenBounds = mEffectiveTransform.transform(mBounds);
+
+ // Add any buffer scaling to the layer's children.
+ ui::Transform bufferScaleTransform = getBufferScaleTransform();
for (const sp<Layer>& child : mDrawingChildren) {
- child->computeBounds(mBounds, getTransformWithScale());
+ child->computeBounds(getBoundsPreScaling(bufferScaleTransform),
+ getTransformWithScale(bufferScaleTransform));
}
}
@@ -1436,7 +1454,9 @@
void Layer::setChildrenDrawingParent(const sp<Layer>& newParent) {
for (const sp<Layer>& child : mDrawingChildren) {
child->mDrawingParent = newParent;
- child->computeBounds(newParent->mBounds, newParent->getTransformWithScale());
+ child->computeBounds(newParent->mBounds,
+ newParent->getTransformWithScale(
+ newParent->getBufferScaleTransform()));
}
}
@@ -1768,9 +1788,13 @@
}
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
+ return getRoundedCornerStateInternal(mSourceBounds);
+}
+
+Layer::RoundedCornerState Layer::getRoundedCornerStateInternal(const FloatRect bounds) const {
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
- RoundedCornerState parentState = p->getRoundedCornerState();
+ RoundedCornerState parentState = p->getRoundedCornerStateInternal(bounds);
if (parentState.radius > 0) {
ui::Transform t = getActiveTransform(getDrawingState());
t = t.inverse();
@@ -1784,7 +1808,9 @@
}
}
const float radius = getDrawingState().cornerRadius;
- return radius > 0 ? RoundedCornerState(getBounds(), radius) : RoundedCornerState();
+ return radius > 0
+ ? RoundedCornerState(bounds.intersect(getCrop(getDrawingState()).toFloatRect()), radius)
+ : RoundedCornerState();
}
void Layer::commitChildList() {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index aba3ff2..b7cfc16 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -361,9 +361,15 @@
// Compute bounds for the layer and cache the results.
void computeBounds(FloatRect parentBounds, ui::Transform parentTransform);
+ // Returns the buffer scale transform if a scaling mode is set.
+ ui::Transform getBufferScaleTransform() const;
+
// Get effective layer transform, taking into account all its parent transform with any
// scaling if the parent scaling more is not NATIVE_WINDOW_SCALING_MODE_FREEZE.
- ui::Transform getTransformWithScale() const;
+ ui::Transform getTransformWithScale(const ui::Transform& bufferScaleTransform) const;
+
+ // Returns the bounds of the layer without any buffer scaling.
+ FloatRect getBoundsPreScaling(const ui::Transform& bufferScaleTransform) const;
int32_t getSequence() const { return sequence; }
@@ -901,6 +907,8 @@
*/
Rect getCroppedBufferSize(const Layer::State& s) const;
+ RoundedCornerState getRoundedCornerStateInternal(const FloatRect bounds) const;
+
// Cached properties computed from drawing state
// Effective transform taking into account parent transforms and any parent scaling.
ui::Transform mEffectiveTransform;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 5296da9..6599f9e 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -789,31 +789,6 @@
StringAppendF(&result, "current monotonic time: %" PRId64 "\n", now);
}
-// TODO(b/113612090): Figure out how much of this is still relevant.
-// We need to determine the time when a buffer acquired now will be
-// displayed. This can be calculated:
-// time when previous buffer's actual-present fence was signaled
-// + current display refresh rate * HWC latency
-// + a little extra padding
-//
-// Buffer producers are expected to set their desired presentation time
-// based on choreographer time stamps, which (coming from vsync events)
-// will be slightly later then the actual-present timing. If we get a
-// desired-present time that is unintentionally a hair after the next
-// vsync, we'll hold the frame when we really want to display it. We
-// need to take the offset between actual-present and reported-vsync
-// into account.
-//
-// If the system is configured without a DispSync phase offset for the app,
-// we also want to throw in a bit of padding to avoid edge cases where we
-// just barely miss. We want to do it here, not in every app. A major
-// source of trouble is the app's use of the display's ideal refresh time
-// (via Display.getRefreshRate()), which could be off of the actual refresh
-// by a few percent, with the error multiplied by the number of frames
-// between now and when the buffer should be displayed.
-//
-// If the refresh reported to the app has a phase offset, we shouldn't need
-// to tweak anything here.
nsecs_t DispSync::expectedPresentTime() {
// The HWC doesn't currently have a way to report additional latency.
// Assume that whatever we submit now will appear right after the flip.
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index d5e3349..67e6de9 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -135,7 +135,7 @@
public:
using InterceptVSyncsCallback = std::function<void(nsecs_t)>;
- // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
+ // TODO(b/128863962): Once the Scheduler is complete this constructor will become obsolete.
EventThread(VSyncSource*, InterceptVSyncsCallback, const char* threadName);
EventThread(std::unique_ptr<VSyncSource>, InterceptVSyncsCallback, const char* threadName);
~EventThread();
@@ -169,7 +169,7 @@
using DisplayEventConsumers = std::vector<sp<EventThreadConnection>>;
- // TODO(b/113612090): Once the Scheduler is complete this constructor will become obsolete.
+ // TODO(b/128863962): Once the Scheduler is complete this constructor will become obsolete.
EventThread(VSyncSource* src, std::unique_ptr<VSyncSource> uniqueSrc,
InterceptVSyncsCallback interceptVSyncsCallback, const char* threadName);
@@ -186,10 +186,7 @@
// Implements VSyncSource::Callback
void onVSyncEvent(nsecs_t timestamp) override;
- // Acquires mutex and requests next vsync.
- void requestNextVsyncInternal(const sp<EventThreadConnection>& connection) EXCLUDES(mMutex);
-
- // TODO(b/113612090): Once the Scheduler is complete this pointer will become obsolete.
+ // TODO(b/128863962): Once the Scheduler is complete this pointer will become obsolete.
VSyncSource* mVSyncSource GUARDED_BY(mMutex) = nullptr;
std::unique_ptr<VSyncSource> mVSyncSourceUnique GUARDED_BY(mMutex) = nullptr;
diff --git a/services/surfaceflinger/Scheduler/MessageQueue.h b/services/surfaceflinger/Scheduler/MessageQueue.h
index 56a00c0..245a8ac 100644
--- a/services/surfaceflinger/Scheduler/MessageQueue.h
+++ b/services/surfaceflinger/Scheduler/MessageQueue.h
@@ -85,7 +85,7 @@
virtual ~MessageQueue();
virtual void init(const sp<SurfaceFlinger>& flinger) = 0;
- // TODO(akrulec): Remove this function once everything is migrated to Scheduler.
+ // TODO(b/128863962): Remove this function once everything is migrated to Scheduler.
virtual void setEventThread(EventThread* events, ResyncCallback resyncCallback) = 0;
virtual void setEventConnection(const sp<EventThreadConnection>& connection) = 0;
virtual void waitMessage() = 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ca94e15..4c4a29b 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -157,6 +157,28 @@
return false;
}
+bool isHdrColorMode(const ColorMode colorMode) {
+ switch (colorMode) {
+ case ColorMode::BT2100_PQ:
+ case ColorMode::BT2100_HLG:
+ return true;
+ case ColorMode::DISPLAY_P3:
+ case ColorMode::ADOBE_RGB:
+ case ColorMode::DCI_P3:
+ case ColorMode::BT2020:
+ case ColorMode::DISPLAY_BT2020:
+ case ColorMode::NATIVE:
+ case ColorMode::STANDARD_BT601_625:
+ case ColorMode::STANDARD_BT601_625_UNADJUSTED:
+ case ColorMode::STANDARD_BT601_525:
+ case ColorMode::STANDARD_BT601_525_UNADJUSTED:
+ case ColorMode::STANDARD_BT709:
+ case ColorMode::SRGB:
+ return false;
+ }
+ return false;
+}
+
ui::Transform::orientation_flags fromSurfaceComposerRotation(ISurfaceComposer::Rotation rotation) {
switch (rotation) {
case ISurfaceComposer::eRotateNone:
@@ -1223,7 +1245,7 @@
auto resyncCallback =
mScheduler->makeResyncCallback(std::bind(&SurfaceFlinger::getVsyncPeriod, this));
- // TODO(akrulec): Part of the Injector should be refactored, so that it
+ // TODO(b/128863962): Part of the Injector should be refactored, so that it
// can be passed to Scheduler.
if (enable) {
ALOGV("VSync Injections enabled");
@@ -1836,7 +1858,9 @@
const auto& displayState = display->getState();
layer->setPerFrameData(displayDevice, displayState.transform, displayState.viewport,
- displayDevice->getSupportedPerFrameMetadata(), targetDataspace);
+ displayDevice->getSupportedPerFrameMetadata(),
+ isHdrColorMode(displayState.colorMode) ? Dataspace::UNKNOWN
+ : targetDataspace);
}
}
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index f1c4347..db78f1d 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -60,7 +60,7 @@
void SurfaceTracing::notify(const char* where) {
std::lock_guard<std::mutex> sfLock(mFlinger.mDrawingStateLock);
- mWhere = strdup(where);
+ mWhere = where;
mConditionalVariable.notify_one();
}
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index a75ac61..9484480 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -80,7 +80,7 @@
const SurfaceFlinger& mFlinger;
- char* mWhere;
+ const char* mWhere = "";
status_t mLastErr = NO_ERROR;
std::thread mThread;
std::condition_variable mConditionalVariable;
diff --git a/services/surfaceflinger/tests/Transaction_test.cpp b/services/surfaceflinger/tests/Transaction_test.cpp
index bc5642e..d62afa5 100644
--- a/services/surfaceflinger/tests/Transaction_test.cpp
+++ b/services/surfaceflinger/tests/Transaction_test.cpp
@@ -4307,7 +4307,7 @@
protected:
void SetUp() override {
LayerUpdateTest::SetUp();
- mChild = createSurface(mClient, "Child surface", 10, 10, PIXEL_FORMAT_RGBA_8888, 0,
+ mChild = createSurface(mClient, "Child surface", 10, 15, PIXEL_FORMAT_RGBA_8888, 0,
mFGSurfaceControl.get());
fillSurfaceRGBA8(mChild, 200, 200, 200);
@@ -4413,6 +4413,32 @@
}
}
+// A child with a scale transform should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildLayerScalingCroppedByParent) {
+ asTransaction([&](Transaction& t) {
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setPosition(mChild, 0, 0);
+ });
+
+ // Find the boundary between the parent and child.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 9);
+ mCapture->expectFGColor(10, 10);
+ }
+
+ asTransaction([&](Transaction& t) { t.setMatrix(mChild, 10.0, 0, 0, 10.0); });
+
+ // The child should fill its parent bounds and be cropped by it.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+}
+
TEST_F(ChildLayerTest, ChildLayerAlpha) {
fillSurfaceRGBA8(mBGSurfaceControl, 0, 0, 254);
fillSurfaceRGBA8(mFGSurfaceControl, 254, 0, 0);
@@ -4649,8 +4675,8 @@
mCapture = screenshot();
// We've positioned the child in the top left.
mCapture->expectChildColor(0, 0);
- // But it's only 10x10.
- mCapture->expectFGColor(10, 10);
+ // But it's only 10x15.
+ mCapture->expectFGColor(10, 15);
}
asTransaction([&](Transaction& t) {
@@ -4664,9 +4690,9 @@
// We've positioned the child in the top left.
mCapture->expectChildColor(0, 0);
mCapture->expectChildColor(10, 10);
- mCapture->expectChildColor(19, 19);
- // And now it should be scaled all the way to 20x20
- mCapture->expectFGColor(20, 20);
+ mCapture->expectChildColor(19, 29);
+ // And now it should be scaled all the way to 20x30
+ mCapture->expectFGColor(20, 30);
}
}
@@ -4682,8 +4708,9 @@
mCapture = screenshot();
// We've positioned the child in the top left.
mCapture->expectChildColor(0, 0);
- // But it's only 10x10.
- mCapture->expectFGColor(10, 10);
+ mCapture->expectChildColor(9, 14);
+ // But it's only 10x15.
+ mCapture->expectFGColor(10, 15);
}
// We set things up as in b/37673612 so that there is a mismatch between the buffer size and
// the WM specified state size.
@@ -4704,6 +4731,115 @@
}
}
+// A child with a buffer transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferTransform) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setSize(mChild, 100, 100);
+ });
+ fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ mCapture = screenshot();
+
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) { t.setSize(mFGSurfaceControl, 128, 64); });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ // Apply a 90 transform on the buffer.
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 64, 128);
+ fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ // The child should be cropped by the new parent bounds.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(99, 63);
+ mCapture->expectFGColor(100, 63);
+ mCapture->expectBGColor(128, 64);
+ }
+}
+
+// A child with a scale transform from its parents should be cropped by its parent bounds.
+TEST_F(ChildLayerTest, ChildCroppedByParentWithBufferScale) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ t.setSize(mChild, 200, 200);
+ });
+ fillSurfaceRGBA8(mChild, 200, 200, 200);
+
+ {
+ mCapture = screenshot();
+
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(63, 63);
+ mCapture->expectBGColor(64, 64);
+ }
+
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ // Set a scaling by 2.
+ t.setSize(mFGSurfaceControl, 128, 128);
+ });
+
+ // Child should inherit its parents scale but should be cropped by its parent bounds.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(127, 127);
+ mCapture->expectBGColor(128, 128);
+ }
+}
+
+// Regression test for b/127368943
+// Child should ignore the buffer transform but apply parent scale transform.
+TEST_F(ChildLayerTest, ChildrenWithParentBufferTransformAndScale) {
+ asTransaction([&](Transaction& t) {
+ t.show(mChild);
+ t.setPosition(mChild, 0, 0);
+ t.setPosition(mFGSurfaceControl, 0, 0);
+ });
+
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(9, 14);
+ mCapture->expectFGColor(10, 15);
+ }
+
+ // Change the size of the foreground to 128 * 64 so we can test rotation as well.
+ asTransaction([&](Transaction& t) {
+ t.setOverrideScalingMode(mFGSurfaceControl, NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW);
+ t.setSize(mFGSurfaceControl, 128, 64);
+ });
+ sp<Surface> s = mFGSurfaceControl->getSurface();
+ auto anw = static_cast<ANativeWindow*>(s.get());
+ // Apply a 90 transform on the buffer and submit a buffer half the expected size so that we
+ // have an effective scale of 2.0 applied to the buffer along with a rotation transform.
+ native_window_set_buffers_transform(anw, NATIVE_WINDOW_TRANSFORM_ROT_90);
+ native_window_set_buffers_dimensions(anw, 32, 64);
+ fillSurfaceRGBA8(mFGSurfaceControl, 195, 63, 63);
+ waitForPostedBuffers();
+
+ // The child should ignore the buffer transform but apply the 2.0 scale from parent.
+ {
+ mCapture = screenshot();
+ mCapture->expectChildColor(0, 0);
+ mCapture->expectChildColor(19, 29);
+ mCapture->expectFGColor(20, 30);
+ }
+}
+
TEST_F(ChildLayerTest, Bug36858924) {
// Destroy the child layer
mChild.clear();
@@ -4857,6 +4993,7 @@
mCapture->checkPixel(10, 10, 255, 255, 255);
}
}
+
class BoundlessLayerTest : public LayerUpdateTest {
protected:
std::unique_ptr<ScreenCapture> mCapture;