Merge "Add concept of gesture input monitors."
diff --git a/cmds/installd/view_compiler.cpp b/cmds/installd/view_compiler.cpp
index f1ac717..60d6492 100644
--- a/cmds/installd/view_compiler.cpp
+++ b/cmds/installd/view_compiler.cpp
@@ -45,7 +45,7 @@
// and pass file descriptors.
// Open input file
- unique_fd infd{open(apk_path, 0)};
+ unique_fd infd{open(apk_path, O_RDONLY)}; // NOLINT(android-cloexec-open)
if (infd.get() < 0) {
PLOG(ERROR) << "Could not open input file: " << apk_path;
return false;
@@ -53,7 +53,7 @@
// Set up output file. viewcompiler can't open outputs by fd, but it can write to stdout, so
// we close stdout and open it towards the right output.
- unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY, 0644)};
+ unique_fd outfd{open(out_dex_file, O_CREAT | O_TRUNC | O_WRONLY | O_CLOEXEC, 0644)};
if (outfd.get() < 0) {
PLOG(ERROR) << "Could not open output file: " << out_dex_file;
return false;
@@ -62,10 +62,6 @@
PLOG(ERROR) << "Could not change output file permissions";
return false;
}
- if (close(STDOUT_FILENO) != 0) {
- PLOG(ERROR) << "Could not close stdout";
- return false;
- }
if (dup2(outfd, STDOUT_FILENO) < 0) {
PLOG(ERROR) << "Could not duplicate output file descriptor";
return false;
@@ -96,4 +92,4 @@
}
} // namespace installd
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/cmds/installd/view_compiler.h b/cmds/installd/view_compiler.h
index f7c6e57..aa141ca 100644
--- a/cmds/installd/view_compiler.h
+++ b/cmds/installd/view_compiler.h
@@ -26,4 +26,4 @@
} // namespace installd
} // namespace android
-#endif // VIEW_COMPILER_H_
\ No newline at end of file
+#endif // VIEW_COMPILER_H_
diff --git a/data/etc/android.hardware.nfc.ese.xml b/data/etc/android.hardware.nfc.ese.xml
new file mode 100644
index 0000000..6642bb2
--- /dev/null
+++ b/data/etc/android.hardware.nfc.ese.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This feature indicates that the device supports eSE-based NFC card
+ emulation -->
+<permissions>
+ <feature name="android.hardware.nfc.ese" />
+</permissions>
diff --git a/data/etc/android.hardware.nfc.uicc.xml b/data/etc/android.hardware.nfc.uicc.xml
new file mode 100644
index 0000000..4f12de4
--- /dev/null
+++ b/data/etc/android.hardware.nfc.uicc.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This feature indicates that the device supports uicc-based NFC card
+ emulation -->
+<permissions>
+ <feature name="android.hardware.nfc.uicc" />
+</permissions>
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index a595c01..5427ff8 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -76,14 +76,6 @@
// Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER
#define STRICT_MODE_PENALTY_GATHER (1 << 31)
-// XXX This can be made public if we want to provide
-// support for typed data.
-struct small_flat_data
-{
- uint32_t type;
- uint32_t data;
-};
-
namespace android {
static pthread_mutex_t gParcelGlobalAllocSizeLock = PTHREAD_MUTEX_INITIALIZER;
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 79db0cb..63f49dd 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -214,15 +214,6 @@
// already be invalid.
ssize_t ProcessState::getKernelReferences(size_t buf_count, uintptr_t* buf)
{
- // TODO: remove these when they are defined by bionic's binder.h
- struct binder_node_debug_info {
- binder_uintptr_t ptr;
- binder_uintptr_t cookie;
- __u32 has_strong_ref;
- __u32 has_weak_ref;
- };
-#define BINDER_GET_NODE_DEBUG_INFO _IOWR('b', 11, struct binder_node_debug_info)
-
binder_node_debug_info info = {};
uintptr_t* end = buf ? buf + buf_count : nullptr;
diff --git a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
index ccde12a..b1c577e 100644
--- a/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
+++ b/libs/binder/aidl/android/content/pm/IPackageManagerNative.aidl
@@ -59,4 +59,22 @@
* Unknown packages are mapped to false.
*/
boolean[] isAudioPlaybackCaptureAllowed(in @utf8InCpp String[] packageNames);
+
+ /* ApplicationInfo.isSystemApp() == true */
+ const int LOCATION_SYSTEM = 0x1;
+ /* ApplicationInfo.isVendor() == true */
+ const int LOCATION_VENDOR = 0x2;
+ /* ApplicationInfo.isProduct() == true */
+ const int LOCATION_PRODUCT = 0x4;
+ /* ApplicationInfo.isProductServices() == true */
+ const int LOCATION_PRODUCT_SERVICES = 0x8;
+
+ /**
+ * Returns a set of bitflags about package location.
+ * LOCATION_SYSTEM: getApplicationInfo(packageName).isSystemApp()
+ * LOCATION_VENDOR: getApplicationInfo(packageName).isVendor()
+ * LOCATION_PRODUCT: getApplicationInfo(packageName).isProduct()
+ * LOCATION_PRODUCT_SERVICES: getApplicationInfo(packageName).isProductService()
+ */
+ int getLocationFlags(in @utf8InCpp String packageName);
}
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
index 7b086d0..5f324c7 100644
--- a/libs/binder/include/binder/ActivityManager.h
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -47,23 +47,24 @@
PROCESS_STATE_PERSISTENT_UI = 1,
PROCESS_STATE_TOP = 2,
PROCESS_STATE_FOREGROUND_SERVICE_LOCATION = 3,
- PROCESS_STATE_FOREGROUND_SERVICE = 4,
- PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 5,
- PROCESS_STATE_IMPORTANT_FOREGROUND = 6,
- PROCESS_STATE_IMPORTANT_BACKGROUND = 7,
- PROCESS_STATE_TRANSIENT_BACKGROUND = 8,
- PROCESS_STATE_BACKUP = 9,
- PROCESS_STATE_SERVICE = 10,
- PROCESS_STATE_RECEIVER = 11,
- PROCESS_STATE_TOP_SLEEPING = 12,
- PROCESS_STATE_HEAVY_WEIGHT = 13,
- PROCESS_STATE_HOME = 14,
- PROCESS_STATE_LAST_ACTIVITY = 15,
- PROCESS_STATE_CACHED_ACTIVITY = 16,
- PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 17,
- PROCESS_STATE_CACHED_RECENT = 18,
- PROCESS_STATE_CACHED_EMPTY = 19,
- PROCESS_STATE_NONEXISTENT = 20,
+ PROCESS_STATE_BOUND_TOP = 4,
+ PROCESS_STATE_FOREGROUND_SERVICE = 5,
+ PROCESS_STATE_BOUND_FOREGROUND_SERVICE = 6,
+ PROCESS_STATE_IMPORTANT_FOREGROUND = 7,
+ PROCESS_STATE_IMPORTANT_BACKGROUND = 8,
+ PROCESS_STATE_TRANSIENT_BACKGROUND = 9,
+ PROCESS_STATE_BACKUP = 10,
+ PROCESS_STATE_SERVICE = 11,
+ PROCESS_STATE_RECEIVER = 12,
+ PROCESS_STATE_TOP_SLEEPING = 13,
+ PROCESS_STATE_HEAVY_WEIGHT = 14,
+ PROCESS_STATE_HOME = 15,
+ PROCESS_STATE_LAST_ACTIVITY = 16,
+ PROCESS_STATE_CACHED_ACTIVITY = 17,
+ PROCESS_STATE_CACHED_ACTIVITY_CLIENT = 18,
+ PROCESS_STATE_CACHED_RECENT = 19,
+ PROCESS_STATE_CACHED_EMPTY = 20,
+ PROCESS_STATE_NONEXISTENT = 21,
};
ActivityManager();
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 5fb3f0b..d87228f 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -59,6 +59,13 @@
}
}
+void BufferQueue::ProxyConsumerListener::onBufferAllocated(const BufferItem& item) {
+ sp<ConsumerListener> listener(mConsumerListener.promote());
+ if (listener != nullptr) {
+ listener->onBufferAllocated(item);
+ }
+}
+
void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
sp<ConsumerListener> listener(mConsumerListener.promote());
if (listener != nullptr) {
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index f2d5c8e..776c6e6 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -58,7 +58,7 @@
int numDroppedBuffers = 0;
sp<IProducerListener> listener;
{
- Mutex::Autolock lock(mCore->mMutex);
+ std::unique_lock<std::mutex> lock(mCore->mMutex);
// Check that the consumer doesn't currently have the maximum number of
// buffers acquired. We allow the max buffer count to be exceeded by one
@@ -203,7 +203,7 @@
if (sharedBufferAvailable && mCore->mQueue.empty()) {
// make sure the buffer has finished allocating before acquiring it
- mCore->waitWhileAllocatingLocked();
+ mCore->waitWhileAllocatingLocked(lock);
slot = mCore->mSharedBufferSlot;
@@ -264,7 +264,7 @@
// We might have freed a slot while dropping old buffers, or the producer
// may be blocked waiting for the number of buffers in the queue to
// decrease.
- mCore->mDequeueCondition.broadcast();
+ mCore->mDequeueCondition.notify_all();
ATRACE_INT(mCore->mConsumerName.string(),
static_cast<int32_t>(mCore->mQueue.size()));
@@ -286,7 +286,7 @@
ATRACE_CALL();
ATRACE_BUFFER_INDEX(slot);
BQ_LOGV("detachBuffer: slot %d", slot);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
@@ -312,7 +312,7 @@
mCore->mActiveBuffers.erase(slot);
mCore->mFreeSlots.insert(slot);
mCore->clearBufferSlotLocked(slot);
- mCore->mDequeueCondition.broadcast();
+ mCore->mDequeueCondition.notify_all();
VALIDATE_CONSISTENCY();
return NO_ERROR;
@@ -330,7 +330,7 @@
return BAD_VALUE;
}
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mSharedBufferMode) {
BQ_LOGE("attachBuffer: cannot attach a buffer in shared buffer mode");
@@ -422,7 +422,7 @@
sp<IProducerListener> listener;
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
// If the frame number has changed because the buffer has been reallocated,
// we can ignore this releaseBuffer for the old buffer.
@@ -461,7 +461,7 @@
listener = mCore->mConnectedProducerListener;
BQ_LOGV("releaseBuffer: releasing slot %d", slot);
- mCore->mDequeueCondition.broadcast();
+ mCore->mDequeueCondition.notify_all();
VALIDATE_CONSISTENCY();
} // Autolock scope
@@ -485,7 +485,7 @@
BQ_LOGV("connect: controlledByApp=%s",
controlledByApp ? "true" : "false");
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("connect: BufferQueue has been abandoned");
@@ -503,7 +503,7 @@
BQ_LOGV("disconnect");
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mConsumerListener == nullptr) {
BQ_LOGE("disconnect: no consumer is connected");
@@ -515,7 +515,7 @@
mCore->mQueue.clear();
mCore->freeAllBuffersLocked();
mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
- mCore->mDequeueCondition.broadcast();
+ mCore->mDequeueCondition.notify_all();
return NO_ERROR;
}
@@ -527,7 +527,7 @@
return BAD_VALUE;
}
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("getReleasedBuffers: BufferQueue has been abandoned");
@@ -569,7 +569,7 @@
BQ_LOGV("setDefaultBufferSize: width=%u height=%u", width, height);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mDefaultWidth = width;
mCore->mDefaultHeight = height;
return NO_ERROR;
@@ -583,7 +583,7 @@
return BAD_VALUE;
}
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mConnectedApi != BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("setMaxBufferCount: producer is already connected");
@@ -623,8 +623,8 @@
sp<IConsumerListener> listener;
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
- mCore->waitWhileAllocatingLocked();
+ std::unique_lock<std::mutex> lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked(lock);
if (mCore->mIsAbandoned) {
BQ_LOGE("setMaxAcquiredBufferCount: consumer is abandoned");
@@ -684,7 +684,7 @@
status_t BufferQueueConsumer::setConsumerName(const String8& name) {
ATRACE_CALL();
BQ_LOGV("setConsumerName: '%s'", name.string());
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mConsumerName = name;
mConsumerName = name;
return NO_ERROR;
@@ -693,7 +693,7 @@
status_t BufferQueueConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
ATRACE_CALL();
BQ_LOGV("setDefaultBufferFormat: %u", defaultFormat);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mDefaultBufferFormat = defaultFormat;
return NO_ERROR;
}
@@ -702,7 +702,7 @@
android_dataspace defaultDataSpace) {
ATRACE_CALL();
BQ_LOGV("setDefaultBufferDataSpace: %u", defaultDataSpace);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mDefaultBufferDataSpace = defaultDataSpace;
return NO_ERROR;
}
@@ -710,7 +710,7 @@
status_t BufferQueueConsumer::setConsumerUsageBits(uint64_t usage) {
ATRACE_CALL();
BQ_LOGV("setConsumerUsageBits: %#" PRIx64, usage);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mConsumerUsageBits = usage;
return NO_ERROR;
}
@@ -718,7 +718,7 @@
status_t BufferQueueConsumer::setConsumerIsProtected(bool isProtected) {
ATRACE_CALL();
BQ_LOGV("setConsumerIsProtected: %s", isProtected ? "true" : "false");
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mConsumerIsProtected = isProtected;
return NO_ERROR;
}
@@ -726,26 +726,26 @@
status_t BufferQueueConsumer::setTransformHint(uint32_t hint) {
ATRACE_CALL();
BQ_LOGV("setTransformHint: %#x", hint);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mTransformHint = hint;
return NO_ERROR;
}
status_t BufferQueueConsumer::getSidebandStream(sp<NativeHandle>* outStream) const {
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
*outStream = mCore->mSidebandStream;
return NO_ERROR;
}
status_t BufferQueueConsumer::getOccupancyHistory(bool forceFlush,
std::vector<OccupancyTracker::Segment>* outHistory) {
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
*outHistory = mCore->mOccupancyTracker.getSegmentHistory(forceFlush);
return NO_ERROR;
}
status_t BufferQueueConsumer::discardFreeBuffers() {
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->discardFreeBuffersLocked();
return NO_ERROR;
}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 960b194..96c55ac 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -110,7 +110,7 @@
BufferQueueCore::~BufferQueueCore() {}
void BufferQueueCore::dumpState(const String8& prefix, String8* outResult) const {
- Mutex::Autolock lock(mMutex);
+ std::lock_guard<std::mutex> lock(mMutex);
outResult->appendFormat("%s- BufferQueue ", prefix.string());
outResult->appendFormat("mMaxAcquiredBufferCount=%d mMaxDequeuedBufferCount=%d\n",
@@ -306,10 +306,10 @@
return true;
}
-void BufferQueueCore::waitWhileAllocatingLocked() const {
+void BufferQueueCore::waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lock) const {
ATRACE_CALL();
while (mIsAllocating) {
- mIsAllocatingCondition.wait(mMutex);
+ mIsAllocatingCondition.wait(lock);
}
}
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index a462b03..72ae375 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -59,14 +59,15 @@
mNextCallbackTicket(0),
mCurrentCallbackTicket(0),
mCallbackCondition(),
- mDequeueTimeout(-1) {}
+ mDequeueTimeout(-1),
+ mDequeueWaitingForAllocation(false) {}
BufferQueueProducer::~BufferQueueProducer() {}
status_t BufferQueueProducer::requestBuffer(int slot, sp<GraphicBuffer>* buf) {
ATRACE_CALL();
BQ_LOGV("requestBuffer: slot %d", slot);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("requestBuffer: BufferQueue has been abandoned");
@@ -101,8 +102,8 @@
sp<IConsumerListener> listener;
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
- mCore->waitWhileAllocatingLocked();
+ std::unique_lock<std::mutex> lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked(lock);
if (mCore->mIsAbandoned) {
BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue has been "
@@ -163,7 +164,7 @@
if (delta < 0) {
listener = mCore->mConsumerListener;
}
- mCore->mDequeueCondition.broadcast();
+ mCore->mDequeueCondition.notify_all();
} // Autolock scope
// Call back without lock held
@@ -180,8 +181,8 @@
sp<IConsumerListener> listener;
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
- mCore->waitWhileAllocatingLocked();
+ std::unique_lock<std::mutex> lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked(lock);
if (mCore->mIsAbandoned) {
BQ_LOGE("setAsyncMode: BufferQueue has been abandoned");
@@ -215,7 +216,7 @@
}
mCore->mAsyncMode = async;
VALIDATE_CONSISTENCY();
- mCore->mDequeueCondition.broadcast();
+ mCore->mDequeueCondition.notify_all();
if (delta < 0) {
listener = mCore->mConsumerListener;
}
@@ -247,7 +248,7 @@
}
status_t BufferQueueProducer::waitForFreeSlotThenRelock(FreeSlotCaller caller,
- int* found) const {
+ std::unique_lock<std::mutex>& lock, int* found) const {
auto callerString = (caller == FreeSlotCaller::Dequeue) ?
"dequeueBuffer" : "attachBuffer";
bool tryAgain = true;
@@ -334,13 +335,13 @@
return WOULD_BLOCK;
}
if (mDequeueTimeout >= 0) {
- status_t result = mCore->mDequeueCondition.waitRelative(
- mCore->mMutex, mDequeueTimeout);
- if (result == TIMED_OUT) {
- return result;
+ std::cv_status result = mCore->mDequeueCondition.wait_for(lock,
+ std::chrono::nanoseconds(mDequeueTimeout));
+ if (result == std::cv_status::timeout) {
+ return TIMED_OUT;
}
} else {
- mCore->mDequeueCondition.wait(mCore->mMutex);
+ mCore->mDequeueCondition.wait(lock);
}
}
} // while (tryAgain)
@@ -354,7 +355,7 @@
FrameEventHistoryDelta* outTimestamps) {
ATRACE_CALL();
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mConsumerName = mCore->mConsumerName;
if (mCore->mIsAbandoned) {
@@ -381,7 +382,16 @@
bool attachedByConsumer = false;
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
+ std::unique_lock<std::mutex> lock(mCore->mMutex);
+
+ // If we don't have a free buffer, but we are currently allocating, we wait until allocation
+ // is finished such that we don't allocate in parallel.
+ if (mCore->mFreeBuffers.empty() && mCore->mIsAllocating) {
+ mDequeueWaitingForAllocation = true;
+ mCore->waitWhileAllocatingLocked(lock);
+ mDequeueWaitingForAllocation = false;
+ mDequeueWaitingForAllocationCondition.notify_all();
+ }
if (format == 0) {
format = mCore->mDefaultBufferFormat;
@@ -398,8 +408,7 @@
int found = BufferItem::INVALID_BUFFER_SLOT;
while (found == BufferItem::INVALID_BUFFER_SLOT) {
- status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue,
- &found);
+ status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Dequeue, lock, &found);
if (status != NO_ERROR) {
return status;
}
@@ -506,7 +515,7 @@
status_t error = graphicBuffer->initCheck();
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (error == NO_ERROR && !mCore->mIsAbandoned) {
graphicBuffer->setGenerationNumber(mCore->mGenerationNumber);
@@ -514,7 +523,7 @@
}
mCore->mIsAllocating = false;
- mCore->mIsAllocatingCondition.broadcast();
+ mCore->mIsAllocatingCondition.notify_all();
if (error != NO_ERROR) {
mCore->mFreeSlots.insert(*outSlot);
@@ -530,6 +539,13 @@
return NO_INIT;
}
+ if (mCore->mConsumerListener != nullptr) {
+ BufferItem item;
+ item.mGraphicBuffer = graphicBuffer;
+ item.mSlot = *outSlot;
+ mCore->mConsumerListener->onBufferAllocated(item);
+ }
+
VALIDATE_CONSISTENCY();
} // Autolock scope
}
@@ -573,7 +589,7 @@
sp<IConsumerListener> listener;
{
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("detachBuffer: BufferQueue has been abandoned");
@@ -608,7 +624,7 @@
mCore->mActiveBuffers.erase(slot);
mCore->mFreeSlots.insert(slot);
mCore->clearBufferSlotLocked(slot);
- mCore->mDequeueCondition.broadcast();
+ mCore->mDequeueCondition.notify_all();
VALIDATE_CONSISTENCY();
listener = mCore->mConsumerListener;
}
@@ -634,7 +650,7 @@
sp<IConsumerListener> listener;
{
- Mutex::Autolock lock(mCore->mMutex);
+ std::unique_lock<std::mutex> lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("detachNextBuffer: BufferQueue has been abandoned");
@@ -652,7 +668,7 @@
return BAD_VALUE;
}
- mCore->waitWhileAllocatingLocked();
+ mCore->waitWhileAllocatingLocked(lock);
if (mCore->mFreeBuffers.empty()) {
return NO_MEMORY;
@@ -690,7 +706,7 @@
return BAD_VALUE;
}
- Mutex::Autolock lock(mCore->mMutex);
+ std::unique_lock<std::mutex> lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("attachBuffer: BufferQueue has been abandoned");
@@ -714,11 +730,11 @@
return BAD_VALUE;
}
- mCore->waitWhileAllocatingLocked();
+ mCore->waitWhileAllocatingLocked(lock);
status_t returnFlags = NO_ERROR;
int found;
- status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, &found);
+ status_t status = waitForFreeSlotThenRelock(FreeSlotCaller::Attach, lock, &found);
if (status != NO_ERROR) {
return status;
}
@@ -791,7 +807,7 @@
uint64_t currentFrameNumber = 0;
BufferItem item;
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("queueBuffer: BufferQueue has been abandoned");
@@ -932,7 +948,7 @@
}
mCore->mBufferHasBeenQueued = true;
- mCore->mDequeueCondition.broadcast();
+ mCore->mDequeueCondition.notify_all();
mCore->mLastQueuedSlot = slot;
output->width = mCore->mDefaultWidth;
@@ -968,9 +984,9 @@
sp<Fence> lastQueuedFence;
{ // scope for the lock
- Mutex::Autolock lock(mCallbackMutex);
+ std::unique_lock<std::mutex> lock(mCallbackMutex);
while (callbackTicket != mCurrentCallbackTicket) {
- mCallbackCondition.wait(mCallbackMutex);
+ mCallbackCondition.wait(lock);
}
if (frameAvailableListener != nullptr) {
@@ -987,7 +1003,7 @@
mLastQueuedTransform = item.mTransform;
++mCurrentCallbackTicket;
- mCallbackCondition.broadcast();
+ mCallbackCondition.notify_all();
}
// Wait without lock held
@@ -1015,7 +1031,7 @@
status_t BufferQueueProducer::cancelBuffer(int slot, const sp<Fence>& fence) {
ATRACE_CALL();
BQ_LOGV("cancelBuffer: slot %d", slot);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mIsAbandoned) {
BQ_LOGE("cancelBuffer: BufferQueue has been abandoned");
@@ -1060,7 +1076,7 @@
}
mSlots[slot].mFence = fence;
- mCore->mDequeueCondition.broadcast();
+ mCore->mDequeueCondition.notify_all();
VALIDATE_CONSISTENCY();
return NO_ERROR;
@@ -1068,7 +1084,7 @@
int BufferQueueProducer::query(int what, int *outValue) {
ATRACE_CALL();
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (outValue == nullptr) {
BQ_LOGE("query: outValue was NULL");
@@ -1136,7 +1152,7 @@
status_t BufferQueueProducer::connect(const sp<IProducerListener>& listener,
int api, bool producerControlledByApp, QueueBufferOutput *output) {
ATRACE_CALL();
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mConsumerName = mCore->mConsumerName;
BQ_LOGV("connect: api=%d producerControlledByApp=%s", api,
producerControlledByApp ? "true" : "false");
@@ -1231,7 +1247,7 @@
int status = NO_ERROR;
sp<IConsumerListener> listener;
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
+ std::unique_lock<std::mutex> lock(mCore->mMutex);
if (mode == DisconnectMode::AllLocal) {
if (BufferQueueThreadState::getCallingPid() != mCore->mConnectedPid) {
@@ -1240,7 +1256,7 @@
api = BufferQueueCore::CURRENTLY_CONNECTED_API;
}
- mCore->waitWhileAllocatingLocked();
+ mCore->waitWhileAllocatingLocked(lock);
if (mCore->mIsAbandoned) {
// It's not really an error to disconnect after the surface has
@@ -1284,7 +1300,7 @@
mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
mCore->mConnectedPid = -1;
mCore->mSidebandStream.clear();
- mCore->mDequeueCondition.broadcast();
+ mCore->mDequeueCondition.notify_all();
listener = mCore->mConsumerListener;
} else if (mCore->mConnectedApi == BufferQueueCore::NO_CONNECTED_API) {
BQ_LOGE("disconnect: not connected (req=%d)", api);
@@ -1314,7 +1330,7 @@
status_t BufferQueueProducer::setSidebandStream(const sp<NativeHandle>& stream) {
sp<IConsumerListener> listener;
{ // Autolock scope
- Mutex::Autolock _l(mCore->mMutex);
+ std::lock_guard<std::mutex> _l(mCore->mMutex);
mCore->mSidebandStream = stream;
listener = mCore->mConsumerListener;
} // Autolock scope
@@ -1336,8 +1352,8 @@
uint64_t allocUsage = 0;
std::string allocName;
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
- mCore->waitWhileAllocatingLocked();
+ std::unique_lock<std::mutex> lock(mCore->mMutex);
+ mCore->waitWhileAllocatingLocked(lock);
if (!mCore->mAllowAllocation) {
BQ_LOGE("allocateBuffers: allocation is not allowed for this "
@@ -1372,16 +1388,16 @@
if (result != NO_ERROR) {
BQ_LOGE("allocateBuffers: failed to allocate buffer (%u x %u, format"
" %u, usage %#" PRIx64 ")", width, height, format, usage);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mIsAllocating = false;
- mCore->mIsAllocatingCondition.broadcast();
+ mCore->mIsAllocatingCondition.notify_all();
return;
}
buffers.push_back(graphicBuffer);
}
{ // Autolock scope
- Mutex::Autolock lock(mCore->mMutex);
+ std::unique_lock<std::mutex> lock(mCore->mMutex);
uint32_t checkWidth = width > 0 ? width : mCore->mDefaultWidth;
uint32_t checkHeight = height > 0 ? height : mCore->mDefaultHeight;
PixelFormat checkFormat = format != 0 ?
@@ -1392,7 +1408,7 @@
// Something changed while we released the lock. Retry.
BQ_LOGV("allocateBuffers: size/format/usage changed while allocating. Retrying.");
mCore->mIsAllocating = false;
- mCore->mIsAllocatingCondition.broadcast();
+ mCore->mIsAllocatingCondition.notify_all();
continue;
}
@@ -1414,14 +1430,27 @@
BQ_LOGV("allocateBuffers: allocated a new buffer in slot %d",
*slot);
+ if (mCore->mConsumerListener != nullptr) {
+ BufferItem item;
+ item.mGraphicBuffer = buffers[i];
+ item.mSlot = *slot;
+ mCore->mConsumerListener->onBufferAllocated(item);
+ }
+
// Make sure the erase is done after all uses of the slot
// iterator since it will be invalid after this point.
mCore->mFreeSlots.erase(slot);
}
mCore->mIsAllocating = false;
- mCore->mIsAllocatingCondition.broadcast();
+ mCore->mIsAllocatingCondition.notify_all();
VALIDATE_CONSISTENCY();
+
+ // If dequeue is waiting for to allocate a buffer, release the lock until it's not
+ // waiting anymore so it can use the buffer we just allocated.
+ while (mDequeueWaitingForAllocation) {
+ mDequeueWaitingForAllocationCondition.wait(lock);
+ }
} // Autolock scope
}
}
@@ -1430,7 +1459,7 @@
ATRACE_CALL();
BQ_LOGV("allowAllocation: %s", allow ? "true" : "false");
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mAllowAllocation = allow;
return NO_ERROR;
}
@@ -1439,14 +1468,14 @@
ATRACE_CALL();
BQ_LOGV("setGenerationNumber: %u", generationNumber);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mGenerationNumber = generationNumber;
return NO_ERROR;
}
String8 BufferQueueProducer::getConsumerName() const {
ATRACE_CALL();
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
BQ_LOGV("getConsumerName: %s", mConsumerName.string());
return mConsumerName;
}
@@ -1455,7 +1484,7 @@
ATRACE_CALL();
BQ_LOGV("setSharedBufferMode: %d", sharedBufferMode);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (!sharedBufferMode) {
mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
}
@@ -1467,7 +1496,7 @@
ATRACE_CALL();
BQ_LOGV("setAutoRefresh: %d", autoRefresh);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
mCore->mAutoRefresh = autoRefresh;
return NO_ERROR;
@@ -1477,7 +1506,7 @@
ATRACE_CALL();
BQ_LOGV("setDequeueTimeout: %" PRId64, timeout);
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
int delta = mCore->getMaxBufferCountLocked(mCore->mAsyncMode, false,
mCore->mMaxBufferCount) - mCore->getMaxBufferCountLocked();
if (!mCore->adjustAvailableSlotsLocked(delta)) {
@@ -1498,7 +1527,7 @@
ATRACE_CALL();
BQ_LOGV("getLastQueuedBuffer");
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
if (mCore->mLastQueuedSlot == BufferItem::INVALID_BUFFER_SLOT) {
*outBuffer = nullptr;
*outFence = Fence::NO_FENCE;
@@ -1534,7 +1563,7 @@
BQ_LOGV("addAndGetFrameTimestamps");
sp<IConsumerListener> listener;
{
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
listener = mCore->mConsumerListener;
}
if (listener != nullptr) {
@@ -1561,7 +1590,7 @@
status_t BufferQueueProducer::getConsumerUsage(uint64_t* outUsage) const {
BQ_LOGV("getConsumerUsage");
- Mutex::Autolock lock(mCore->mMutex);
+ std::lock_guard<std::mutex> lock(mCore->mMutex);
*outUsage = mCore->mConsumerUsageBits;
return NO_ERROR;
}
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index abd9921..1e94cc1 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -131,6 +131,8 @@
}
}
+void ConsumerBase::onBufferAllocated(const BufferItem& /*item*/) {}
+
void ConsumerBase::onBuffersReleased() {
Mutex::Autolock lock(mMutex);
diff --git a/libs/gui/IConsumerListener.cpp b/libs/gui/IConsumerListener.cpp
index 85ac304..ea9045c 100644
--- a/libs/gui/IConsumerListener.cpp
+++ b/libs/gui/IConsumerListener.cpp
@@ -28,7 +28,8 @@
ON_FRAME_REPLACED,
ON_BUFFERS_RELEASED,
ON_SIDEBAND_STREAM_CHANGED,
- LAST = ON_SIDEBAND_STREAM_CHANGED,
+ ON_BUFFER_ALLOCATED,
+ LAST = ON_BUFFER_ALLOCATED,
};
} // Anonymous namespace
@@ -54,6 +55,11 @@
item);
}
+ void onBufferAllocated(const BufferItem& item) override {
+ callRemoteAsync<decltype(&IConsumerListener::onBufferAllocated)>(Tag::ON_BUFFER_ALLOCATED,
+ item);
+ }
+
void onBuffersReleased() override {
callRemoteAsync<decltype(&IConsumerListener::onBuffersReleased)>(Tag::ON_BUFFERS_RELEASED);
}
@@ -89,6 +95,8 @@
return callLocalAsync(data, reply, &IConsumerListener::onFrameAvailable);
case Tag::ON_FRAME_REPLACED:
return callLocalAsync(data, reply, &IConsumerListener::onFrameReplaced);
+ case Tag::ON_BUFFER_ALLOCATED:
+ return callLocalAsync(data, reply, &IConsumerListener::onBufferAllocated);
case Tag::ON_BUFFERS_RELEASED:
return callLocalAsync(data, reply, &IConsumerListener::onBuffersReleased);
case Tag::ON_SIDEBAND_STREAM_CHANGED:
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 14eca43..bf44121 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -360,7 +360,7 @@
data.writeUint32(height);
data.writeInt32(static_cast<int32_t>(format));
data.writeUint64(usage);
- status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply, TF_ONE_WAY);
+ status_t result = remote()->transact(ALLOCATE_BUFFERS, data, &reply, IBinder::FLAG_ONEWAY);
if (result != NO_ERROR) {
ALOGE("allocateBuffers failed to transact: %d", result);
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index b74d675..b586bf3 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -551,8 +551,8 @@
ALOGE("enableVSyncInjections failed to writeBool: %d", result);
return result;
}
- result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS,
- data, &reply, TF_ONE_WAY);
+ result = remote()->transact(BnSurfaceComposer::ENABLE_VSYNC_INJECTIONS, data, &reply,
+ IBinder::FLAG_ONEWAY);
if (result != NO_ERROR) {
ALOGE("enableVSyncInjections failed to transact: %d", result);
return result;
@@ -572,7 +572,8 @@
ALOGE("injectVSync failed to writeInt64: %d", result);
return result;
}
- result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply, TF_ONE_WAY);
+ result = remote()->transact(BnSurfaceComposer::INJECT_VSYNC, data, &reply,
+ IBinder::FLAG_ONEWAY);
if (result != NO_ERROR) {
ALOGE("injectVSync failed to transact: %d", result);
return result;
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index ce88d7b..74cd4f1 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -76,7 +76,11 @@
}
status_t TransactionStats::writeToParcel(Parcel* output) const {
- status_t err = output->writeInt64(latchTime);
+ status_t err = output->writeInt64Vector(callbackIds);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = output->writeInt64(latchTime);
if (err != NO_ERROR) {
return err;
}
@@ -96,7 +100,11 @@
}
status_t TransactionStats::readFromParcel(const Parcel* input) {
- status_t err = input->readInt64(&latchTime);
+ status_t err = input->readInt64Vector(&callbackIds);
+ if (err != NO_ERROR) {
+ return err;
+ }
+ err = input->readInt64(&latchTime);
if (err != NO_ERROR) {
return err;
}
@@ -120,16 +128,11 @@
if (err != NO_ERROR) {
return err;
}
-
- for (const auto& [callbackIds, stats] : transactionStats) {
+ for (const auto& stats : transactionStats) {
err = output->writeParcelable(stats);
if (err != NO_ERROR) {
return err;
}
- err = output->writeInt64Vector(callbackIds);
- if (err != NO_ERROR) {
- return err;
- }
}
return NO_ERROR;
}
@@ -139,18 +142,11 @@
for (int i = 0; i < transactionStats_size; i++) {
TransactionStats stats;
- std::vector<CallbackId> callbackIds;
-
status_t err = input->readParcelable(&stats);
if (err != NO_ERROR) {
return err;
}
- err = input->readInt64Vector(&callbackIds);
- if (err != NO_ERROR) {
- return err;
- }
-
- transactionStats.emplace(callbackIds, stats);
+ transactionStats.push_back(stats);
}
return NO_ERROR;
}
@@ -159,11 +155,8 @@
const std::unordered_set<CallbackId>& callbackIds) {
ListenerStats listenerStats;
listenerStats.listener = listener;
- TransactionStats transactionStats;
- listenerStats.transactionStats.emplace(std::piecewise_construct,
- std::forward_as_tuple(callbackIds.begin(),
- callbackIds.end()),
- std::forward_as_tuple(transactionStats));
+ listenerStats.transactionStats.emplace_back(callbackIds);
+
return listenerStats;
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 56a3fbc..83cf40c 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -203,15 +203,15 @@
* that could possibly exist for the callbacks.
*/
std::unordered_map<sp<IBinder>, sp<SurfaceControl>, IBinderHash> surfaceControls;
- for (const auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
- for (auto callbackId : callbackIds) {
+ for (const auto& transactionStats : listenerStats.transactionStats) {
+ for (auto callbackId : transactionStats.callbackIds) {
auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
surfaceControls.insert(callbackSurfaceControls.begin(), callbackSurfaceControls.end());
}
}
- for (const auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
- for (auto callbackId : callbackIds) {
+ for (const auto& transactionStats : listenerStats.transactionStats) {
+ for (auto callbackId : transactionStats.callbackIds) {
auto& [callbackFunction, callbackSurfaceControls] = mCallbacks[callbackId];
if (!callbackFunction) {
ALOGE("cannot call null callback function, skipping");
@@ -415,7 +415,7 @@
uint64_t cacheId = 0;
status_t ret = BufferCache::getInstance().getCacheId(s->buffer, &cacheId);
if (ret == NO_ERROR) {
- s->what &= ~static_cast<uint32_t>(layer_state_t::eBufferChanged);
+ s->what &= ~static_cast<uint64_t>(layer_state_t::eBufferChanged);
s->buffer = nullptr;
} else {
cacheId = BufferCache::getInstance().cache(s->buffer);
diff --git a/libs/gui/include/gui/BufferQueue.h b/libs/gui/include/gui/BufferQueue.h
index da95274..721427b 100644
--- a/libs/gui/include/gui/BufferQueue.h
+++ b/libs/gui/include/gui/BufferQueue.h
@@ -61,6 +61,7 @@
void onDisconnect() override;
void onFrameAvailable(const BufferItem& item) override;
void onFrameReplaced(const BufferItem& item) override;
+ void onBufferAllocated(const BufferItem& item) override;
void onBuffersReleased() override;
void onSidebandStreamChanged() override;
void addAndGetFrameTimestamps(
diff --git a/libs/gui/include/gui/BufferQueueCore.h b/libs/gui/include/gui/BufferQueueCore.h
index b377a41..0e80283 100644
--- a/libs/gui/include/gui/BufferQueueCore.h
+++ b/libs/gui/include/gui/BufferQueueCore.h
@@ -22,8 +22,6 @@
#include <gui/BufferSlot.h>
#include <gui/OccupancyTracker.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
#include <utils/NativeHandle.h>
#include <utils/RefBase.h>
#include <utils/String8.h>
@@ -33,6 +31,8 @@
#include <list>
#include <set>
+#include <mutex>
+#include <condition_variable>
#define BQ_LOGV(x, ...) ALOGV("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
#define BQ_LOGD(x, ...) ALOGD("[%s] " x, mConsumerName.string(), ##__VA_ARGS__)
@@ -134,7 +134,7 @@
bool adjustAvailableSlotsLocked(int delta);
// waitWhileAllocatingLocked blocks until mIsAllocating is false.
- void waitWhileAllocatingLocked() const;
+ void waitWhileAllocatingLocked(std::unique_lock<std::mutex>& lock) const;
#if DEBUG_ONLY_CODE
// validateConsistencyLocked ensures that the free lists are in sync with
@@ -145,7 +145,7 @@
// mMutex is the mutex used to prevent concurrent access to the member
// variables of BufferQueueCore objects. It must be locked whenever any
// member variable is accessed.
- mutable Mutex mMutex;
+ mutable std::mutex mMutex;
// mIsAbandoned indicates that the BufferQueue will no longer be used to
// consume image buffers pushed to it using the IGraphicBufferProducer
@@ -219,7 +219,7 @@
// mDequeueCondition is a condition variable used for dequeueBuffer in
// synchronous mode.
- mutable Condition mDequeueCondition;
+ mutable std::condition_variable mDequeueCondition;
// mDequeueBufferCannotBlock indicates whether dequeueBuffer is allowed to
// block. This flag is set during connect when both the producer and
@@ -282,7 +282,7 @@
// mIsAllocatingCondition is a condition variable used by producers to wait until mIsAllocating
// becomes false.
- mutable Condition mIsAllocatingCondition;
+ mutable std::condition_variable mIsAllocatingCondition;
// mAllowAllocation determines whether dequeueBuffer is allowed to allocate
// new buffers
diff --git a/libs/gui/include/gui/BufferQueueProducer.h b/libs/gui/include/gui/BufferQueueProducer.h
index 73bc5dd..415e2a6 100644
--- a/libs/gui/include/gui/BufferQueueProducer.h
+++ b/libs/gui/include/gui/BufferQueueProducer.h
@@ -211,7 +211,8 @@
Dequeue,
Attach,
};
- status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, int* found) const;
+ status_t waitForFreeSlotThenRelock(FreeSlotCaller caller, std::unique_lock<std::mutex>& lock,
+ int* found) const;
sp<BufferQueueCore> mCore;
@@ -243,15 +244,22 @@
// (mCore->mMutex) is held, a ticket is retained by the producer. After
// dropping the BufferQueue lock, the producer must wait on the condition
// variable until the current callback ticket matches its retained ticket.
- Mutex mCallbackMutex;
+ std::mutex mCallbackMutex;
int mNextCallbackTicket; // Protected by mCore->mMutex
int mCurrentCallbackTicket; // Protected by mCallbackMutex
- Condition mCallbackCondition;
+ std::condition_variable mCallbackCondition;
// Sets how long dequeueBuffer or attachBuffer will block if a buffer or
// slot is not yet available.
nsecs_t mDequeueTimeout;
+ // If set to true, dequeueBuffer() is currently waiting for buffer allocation to complete.
+ bool mDequeueWaitingForAllocation;
+
+ // Condition variable to signal allocateBuffers() that dequeueBuffer() is no longer waiting for
+ // allocation to complete.
+ std::condition_variable mDequeueWaitingForAllocationCondition;
+
}; // class BufferQueueProducer
} // namespace android
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index 366ced3..7c26482 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -141,6 +141,7 @@
// classes if they want the notification.
virtual void onFrameAvailable(const BufferItem& item) override;
virtual void onFrameReplaced(const BufferItem& item) override;
+ virtual void onBufferAllocated(const BufferItem& item) override;
virtual void onBuffersReleased() override;
virtual void onSidebandStreamChanged() override;
diff --git a/libs/gui/include/gui/IConsumerListener.h b/libs/gui/include/gui/IConsumerListener.h
index c082882..03fefbe 100644
--- a/libs/gui/include/gui/IConsumerListener.h
+++ b/libs/gui/include/gui/IConsumerListener.h
@@ -61,6 +61,13 @@
// This is called without any lock held and can be called concurrently by multiple threads.
virtual void onFrameReplaced(const BufferItem& /* item */) {} /* Asynchronous */
+ // onBufferAllocated is called to notify the buffer consumer that the BufferQueue has allocated
+ // a GraphicBuffer for a particular slot. Only the GraphicBuffer pointer and the slot ID will
+ // be populated.
+ //
+ // This is called without any lock held and can be called concurrently by multiple threads.
+ virtual void onBufferAllocated(const BufferItem& /* item */) {} /* Asynchronous */
+
// onBuffersReleased is called to notify the buffer consumer that the BufferQueue has released
// its references to one or more GraphicBuffers contained in its slots. The buffer consumer
// should then call BufferQueue::getReleasedBuffers to retrieve the list of buffers.
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index 29ab026..774ad46 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -34,18 +34,6 @@
using CallbackId = int64_t;
-struct CallbackIdsHash {
- // CallbackId vectors have several properties that let us get away with this simple hash.
- // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is
- // empty we can still hash 0.
- // 2) CallbackId vectors for the same listener either are identical or contain none of the
- // same members. It is sufficient to just check the first CallbackId in the vectors. If
- // they match, they are the same. If they do not match, they are not the same.
- std::size_t operator()(const std::vector<CallbackId> callbackIds) const {
- return std::hash<CallbackId>{}((callbackIds.size() == 0) ? 0 : callbackIds.front());
- }
-};
-
class SurfaceStats : public Parcelable {
public:
status_t writeToParcel(Parcel* output) const override;
@@ -65,6 +53,15 @@
status_t writeToParcel(Parcel* output) const override;
status_t readFromParcel(const Parcel* input) override;
+ TransactionStats() = default;
+ TransactionStats(const std::vector<CallbackId>& ids) : callbackIds(ids) {}
+ TransactionStats(const std::unordered_set<CallbackId>& ids)
+ : callbackIds(ids.begin(), ids.end()) {}
+ TransactionStats(const std::vector<CallbackId>& ids, nsecs_t latch, const sp<Fence>& present,
+ const std::vector<SurfaceStats>& surfaces)
+ : callbackIds(ids), latchTime(latch), presentFence(present), surfaceStats(surfaces) {}
+
+ std::vector<CallbackId> callbackIds;
nsecs_t latchTime = -1;
sp<Fence> presentFence = nullptr;
std::vector<SurfaceStats> surfaceStats;
@@ -79,7 +76,7 @@
const std::unordered_set<CallbackId>& callbackIds);
sp<ITransactionCompletedListener> listener;
- std::unordered_map<std::vector<CallbackId>, TransactionStats, CallbackIdsHash> transactionStats;
+ std::vector<TransactionStats> transactionStats;
};
class ITransactionCompletedListener : public IInterface {
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index 1980f50..faf6d2a 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -248,7 +248,8 @@
bool useContextPriority = extensions.hasContextPriority() &&
(featureFlags & RenderEngine::USE_HIGH_PRIORITY_CONTEXT);
EGLContext protectedContext = EGL_NO_CONTEXT;
- if (extensions.hasProtectedContent()) {
+ if ((featureFlags & RenderEngine::ENABLE_PROTECTED_CONTEXT) &&
+ extensions.hasProtectedContent()) {
protectedContext = createEglContext(display, config, nullptr, useContextPriority,
Protection::PROTECTED);
ALOGE_IF(protectedContext == EGL_NO_CONTEXT, "Can't create protected context");
@@ -626,23 +627,26 @@
}
}
-status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
- sp<Fence> bufferFence) {
+status_t GLESRenderEngine::cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) {
+ std::lock_guard<std::mutex> lock(mRenderingMutex);
+ return cacheExternalTextureBufferLocked(buffer);
+}
+
+status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName,
+ const sp<GraphicBuffer>& buffer,
+ const sp<Fence>& bufferFence) {
std::lock_guard<std::mutex> lock(mRenderingMutex);
return bindExternalTextureBufferLocked(texName, buffer, bufferFence);
}
-status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName,
- sp<GraphicBuffer> buffer,
- sp<Fence> bufferFence) {
+status_t GLESRenderEngine::cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer) {
if (buffer == nullptr) {
return BAD_VALUE;
}
- ATRACE_CALL();
- auto cachedImage = mImageCache.find(buffer->getId());
- if (cachedImage != mImageCache.end()) {
- bindExternalTextureImage(texName, *cachedImage->second);
+ ATRACE_CALL();
+
+ if (mImageCache.count(buffer->getId()) > 0) {
return NO_ERROR;
}
@@ -654,11 +658,32 @@
ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
buffer->getPixelFormat());
+ return NO_INIT;
+ }
+ mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
+
+ return NO_ERROR;
+}
+
+status_t GLESRenderEngine::bindExternalTextureBufferLocked(uint32_t texName,
+ const sp<GraphicBuffer>& buffer,
+ const sp<Fence>& bufferFence) {
+ ATRACE_CALL();
+ status_t cacheResult = cacheExternalTextureBufferLocked(buffer);
+
+ if (cacheResult != NO_ERROR) {
+ return cacheResult;
+ }
+
+ auto cachedImage = mImageCache.find(buffer->getId());
+
+ if (cachedImage == mImageCache.end()) {
+ // We failed creating the image if we got here, so bail out.
bindExternalTextureImage(texName, *createImage());
return NO_INIT;
}
- bindExternalTextureImage(texName, *newImage);
+ bindExternalTextureImage(texName, *cachedImage->second);
// Wait for the new buffer to be ready.
if (bufferFence != nullptr && bufferFence->isValid()) {
@@ -680,7 +705,6 @@
}
}
}
- mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
return NO_ERROR;
}
@@ -720,6 +744,9 @@
// We separate the layer into 3 parts essentially, such that we only turn on blending for the
// top rectangle and the bottom rectangle, and turn off blending for the middle rectangle.
FloatRect bounds = layer.geometry.roundedCornersCrop;
+
+ // Firstly, we need to convert the coordination from layer native coordination space to
+ // device coordination space.
const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform;
const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0);
const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0);
@@ -727,8 +754,28 @@
const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate;
bounds = FloatRect(leftTopCoordinateInBuffer[0], leftTopCoordinateInBuffer[1],
rightBottomCoordinateInBuffer[0], rightBottomCoordinateInBuffer[1]);
- const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
+ // Secondly, if the display is rotated, we need to undo the rotation on coordination and
+ // align the (left, top) and (right, bottom) coordination with the device coordination
+ // space.
+ switch (display.orientation) {
+ case ui::Transform::ROT_90:
+ std::swap(bounds.left, bounds.right);
+ break;
+ case ui::Transform::ROT_180:
+ std::swap(bounds.left, bounds.right);
+ std::swap(bounds.top, bounds.bottom);
+ break;
+ case ui::Transform::ROT_270:
+ std::swap(bounds.top, bounds.bottom);
+ break;
+ default:
+ break;
+ }
+
+ // Finally, we cut the layer into 3 parts, with top and bottom parts having rounded corners
+ // and the middle part without rounded corners.
+ const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius);
setScissor(topRect);
drawMesh(mesh);
@@ -808,12 +855,14 @@
return success;
}
EGLImageKHR GLESRenderEngine::createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer,
- bool isProtected) {
+ bool isProtected,
+ bool useFramebufferCache) {
sp<GraphicBuffer> graphicBuffer = GraphicBuffer::from(nativeBuffer);
- uint64_t bufferId = graphicBuffer->getId();
- for (const auto& image : mFramebufferImageCache) {
- if (image.first == bufferId) {
- return image.second;
+ if (useFramebufferCache) {
+ for (const auto& image : mFramebufferImageCache) {
+ if (image.first == graphicBuffer->getId()) {
+ return image.second;
+ }
}
}
EGLint attributes[] = {
@@ -823,13 +872,15 @@
};
EGLImageKHR image = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
nativeBuffer, attributes);
- if (image != EGL_NO_IMAGE_KHR) {
- if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) {
- EGLImageKHR expired = mFramebufferImageCache.front().second;
- mFramebufferImageCache.pop_front();
- eglDestroyImageKHR(mEGLDisplay, expired);
+ if (useFramebufferCache) {
+ if (image != EGL_NO_IMAGE_KHR) {
+ if (mFramebufferImageCache.size() >= mFramebufferImageCacheSize) {
+ EGLImageKHR expired = mFramebufferImageCache.front().second;
+ mFramebufferImageCache.pop_front();
+ eglDestroyImageKHR(mEGLDisplay, expired);
+ }
+ mFramebufferImageCache.push_back({graphicBuffer->getId(), image});
}
- mFramebufferImageCache.push_back({bufferId, image});
}
return image;
}
@@ -837,7 +888,8 @@
status_t GLESRenderEngine::drawLayers(const DisplaySettings& display,
const std::vector<LayerSettings>& layers,
ANativeWindowBuffer* const buffer,
- base::unique_fd&& bufferFence, base::unique_fd* drawFence) {
+ const bool useFramebufferCache, base::unique_fd&& bufferFence,
+ base::unique_fd* drawFence) {
ATRACE_CALL();
if (layers.empty()) {
ALOGV("Drawing empty layer stack");
@@ -857,7 +909,7 @@
{
std::lock_guard<std::mutex> lock(mRenderingMutex);
- BindNativeBufferAsFramebuffer fbo(*this, buffer);
+ BindNativeBufferAsFramebuffer fbo(*this, buffer, useFramebufferCache);
if (fbo.getStatus() != NO_ERROR) {
ALOGE("Failed to bind framebuffer! Aborting GPU composition for buffer (%p).",
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index 8c8f308..de793c2 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -72,8 +72,9 @@
void genTextures(size_t count, uint32_t* names) override;
void deleteTextures(size_t count, uint32_t const* names) override;
void bindExternalTextureImage(uint32_t texName, const Image& image) override;
- status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence)
- EXCLUDES(mRenderingMutex);
+ status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
+ const sp<Fence>& fence) EXCLUDES(mRenderingMutex);
+ status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) EXCLUDES(mRenderingMutex);
void unbindExternalTextureBuffer(uint64_t bufferId) EXCLUDES(mRenderingMutex);
status_t bindFrameBuffer(Framebuffer* framebuffer) override;
void unbindFrameBuffer(Framebuffer* framebuffer) override;
@@ -83,14 +84,16 @@
bool supportsProtectedContent() const override;
bool useProtectedContext(bool useProtectedContext) override;
status_t drawLayers(const DisplaySettings& display, const std::vector<LayerSettings>& layers,
- ANativeWindowBuffer* buffer, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) EXCLUDES(mRenderingMutex) override;
+ ANativeWindowBuffer* buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence, base::unique_fd* drawFence)
+ EXCLUDES(mRenderingMutex) override;
// internal to RenderEngine
EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
EGLConfig getEGLConfig() const { return mEGLConfig; }
// Creates an output image for rendering to
- EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected);
+ EGLImageKHR createFramebufferImageIfNeeded(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+ bool useFramebufferCache);
// Test-only methods
// Returns true iff mImageCache contains an image keyed by bufferId
@@ -219,8 +222,12 @@
// See bindExternalTextureBuffer above, but requiring that mRenderingMutex
// is held.
- status_t bindExternalTextureBufferLocked(uint32_t texName, sp<GraphicBuffer> buffer,
- sp<Fence> fence) REQUIRES(mRenderingMutex);
+ status_t bindExternalTextureBufferLocked(uint32_t texName, const sp<GraphicBuffer>& buffer,
+ const sp<Fence>& fence) REQUIRES(mRenderingMutex);
+ // See cacheExternalTextureBuffer above, but requiring that mRenderingMutex
+ // is held.
+ status_t cacheExternalTextureBufferLocked(const sp<GraphicBuffer>& buffer)
+ REQUIRES(mRenderingMutex);
std::unique_ptr<Framebuffer> mDrawingBuffer;
diff --git a/libs/renderengine/gl/GLFramebuffer.cpp b/libs/renderengine/gl/GLFramebuffer.cpp
index c45598c..dacf8d3 100644
--- a/libs/renderengine/gl/GLFramebuffer.cpp
+++ b/libs/renderengine/gl/GLFramebuffer.cpp
@@ -41,19 +41,25 @@
glDeleteTextures(1, &mTextureName);
}
-bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) {
+bool GLFramebuffer::setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+ const bool useFramebufferCache) {
ATRACE_CALL();
if (mEGLImage != EGL_NO_IMAGE_KHR) {
+ if (!usingFramebufferCache) {
+ eglDestroyImageKHR(mEGLDisplay, mEGLImage);
+ }
mEGLImage = EGL_NO_IMAGE_KHR;
mBufferWidth = 0;
mBufferHeight = 0;
}
if (nativeBuffer) {
- mEGLImage = mEngine.createFramebufferImageIfNeeded(nativeBuffer, isProtected);
+ mEGLImage = mEngine.createFramebufferImageIfNeeded(nativeBuffer, isProtected,
+ useFramebufferCache);
if (mEGLImage == EGL_NO_IMAGE_KHR) {
return false;
}
+ usingFramebufferCache = useFramebufferCache;
mBufferWidth = nativeBuffer->width;
mBufferHeight = nativeBuffer->height;
}
diff --git a/libs/renderengine/gl/GLFramebuffer.h b/libs/renderengine/gl/GLFramebuffer.h
index 1289fbf..b7650bb 100644
--- a/libs/renderengine/gl/GLFramebuffer.h
+++ b/libs/renderengine/gl/GLFramebuffer.h
@@ -35,7 +35,8 @@
explicit GLFramebuffer(GLESRenderEngine& engine);
~GLFramebuffer() override;
- bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) override;
+ bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+ const bool useFramebufferCache) override;
EGLImageKHR getEGLImage() const { return mEGLImage; }
uint32_t getTextureName() const { return mTextureName; }
uint32_t getFramebufferName() const { return mFramebufferName; }
@@ -46,6 +47,7 @@
GLESRenderEngine& mEngine;
EGLDisplay mEGLDisplay;
EGLImageKHR mEGLImage;
+ bool usingFramebufferCache = false;
uint32_t mTextureName, mFramebufferName;
int32_t mBufferHeight = 0;
diff --git a/libs/renderengine/include/renderengine/DisplaySettings.h b/libs/renderengine/include/renderengine/DisplaySettings.h
index af8de23..9c9884a 100644
--- a/libs/renderengine/include/renderengine/DisplaySettings.h
+++ b/libs/renderengine/include/renderengine/DisplaySettings.h
@@ -20,6 +20,7 @@
#include <ui/GraphicTypes.h>
#include <ui/Rect.h>
#include <ui/Region.h>
+#include <ui/Transform.h>
namespace android {
namespace renderengine {
@@ -56,6 +57,9 @@
// globalTransform, so that it will be in the same coordinate space as the
// rendered layers.
Region clearRegion = Region::INVALID_REGION;
+
+ // The orientation of the physical display.
+ uint32_t orientation = ui::Transform::ROT_0;
};
} // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/Framebuffer.h b/libs/renderengine/include/renderengine/Framebuffer.h
index 66eb9ef..6511127 100644
--- a/libs/renderengine/include/renderengine/Framebuffer.h
+++ b/libs/renderengine/include/renderengine/Framebuffer.h
@@ -27,7 +27,8 @@
public:
virtual ~Framebuffer() = default;
- virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected) = 0;
+ virtual bool setNativeWindowBuffer(ANativeWindowBuffer* nativeBuffer, bool isProtected,
+ const bool useFramebufferCache) = 0;
};
} // namespace renderengine
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index b211551..e707004 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -63,6 +63,9 @@
enum FeatureFlag {
USE_COLOR_MANAGEMENT = 1 << 0, // Device manages color
USE_HIGH_PRIORITY_CONTEXT = 1 << 1, // Use high priority context
+
+ // Create a protected context when if possible
+ ENABLE_PROTECTED_CONTEXT = 1 << 2,
};
static std::unique_ptr<impl::RenderEngine> create(int hwcFormat, uint32_t featureFlags,
@@ -106,8 +109,14 @@
virtual void genTextures(size_t count, uint32_t* names) = 0;
virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
- virtual status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
- sp<Fence> fence) = 0;
+ // Legacy public method used by devices that don't support native fence
+ // synchronization in their GPU driver, as this method provides implicit
+ // synchronization for latching buffers.
+ virtual status_t bindExternalTextureBuffer(uint32_t texName, const sp<GraphicBuffer>& buffer,
+ const sp<Fence>& fence) = 0;
+ // Caches Image resources for this buffer, but does not bind the buffer to
+ // a particular texture.
+ virtual status_t cacheExternalTextureBuffer(const sp<GraphicBuffer>& buffer) = 0;
// Removes internal resources referenced by the bufferId. This method should be
// invoked when the caller will no longer hold a reference to a GraphicBuffer
// and needs to clean up its resources.
@@ -170,6 +179,9 @@
// @param layers The layers to draw onto the display, in Z-order.
// @param buffer The buffer which will be drawn to. This buffer will be
// ready once drawFence fires.
+ // @param useFramebufferCache True if the framebuffer cache should be used.
+ // If an implementation does not cache output framebuffers, then this
+ // parameter does nothing.
// @param bufferFence Fence signalling that the buffer is ready to be drawn
// to.
// @param drawFence A pointer to a fence, which will fire when the buffer
@@ -180,8 +192,8 @@
// now, this always returns NO_ERROR.
virtual status_t drawLayers(const DisplaySettings& display,
const std::vector<LayerSettings>& layers,
- ANativeWindowBuffer* buffer, base::unique_fd&& bufferFence,
- base::unique_fd* drawFence) = 0;
+ ANativeWindowBuffer* buffer, const bool useFramebufferCache,
+ base::unique_fd&& bufferFence, base::unique_fd* drawFence) = 0;
protected:
// Gets a framebuffer to render to. This framebuffer may or may not be
@@ -195,14 +207,16 @@
class BindNativeBufferAsFramebuffer {
public:
- BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer)
+ BindNativeBufferAsFramebuffer(RenderEngine& engine, ANativeWindowBuffer* buffer,
+ const bool useFramebufferCache)
: mEngine(engine), mFramebuffer(mEngine.getFramebufferForDrawing()), mStatus(NO_ERROR) {
- mStatus = mFramebuffer->setNativeWindowBuffer(buffer, mEngine.isProtected())
+ mStatus = mFramebuffer->setNativeWindowBuffer(buffer, mEngine.isProtected(),
+ useFramebufferCache)
? mEngine.bindFrameBuffer(mFramebuffer)
: NO_MEMORY;
}
~BindNativeBufferAsFramebuffer() {
- mFramebuffer->setNativeWindowBuffer(nullptr, false);
+ mFramebuffer->setNativeWindowBuffer(nullptr, false, /*arbitrary*/ true);
mEngine.unbindFrameBuffer(mFramebuffer);
}
status_t getStatus() const { return mStatus; }
diff --git a/libs/renderengine/include/renderengine/mock/Framebuffer.h b/libs/renderengine/include/renderengine/mock/Framebuffer.h
index 7695885..dfb6a4e 100644
--- a/libs/renderengine/include/renderengine/mock/Framebuffer.h
+++ b/libs/renderengine/include/renderengine/mock/Framebuffer.h
@@ -28,7 +28,7 @@
Framebuffer();
~Framebuffer() override;
- MOCK_METHOD2(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool));
+ MOCK_METHOD3(setNativeWindowBuffer, bool(ANativeWindowBuffer*, bool, const bool));
};
} // namespace mock
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index 479c7ac..e33bcfd 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -51,7 +51,9 @@
MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
- MOCK_METHOD3(bindExternalTextureBuffer, status_t(uint32_t, sp<GraphicBuffer>, sp<Fence>));
+ MOCK_METHOD1(cacheExternalTextureBuffer, status_t(const sp<GraphicBuffer>&));
+ MOCK_METHOD3(bindExternalTextureBuffer,
+ status_t(uint32_t, const sp<GraphicBuffer>&, const sp<Fence>&));
MOCK_METHOD1(unbindExternalTextureBuffer, void(uint64_t));
MOCK_CONST_METHOD0(checkErrors, void());
MOCK_METHOD4(setViewportAndProjection,
@@ -77,9 +79,9 @@
MOCK_CONST_METHOD0(isProtected, bool());
MOCK_CONST_METHOD0(supportsProtectedContent, bool());
MOCK_METHOD1(useProtectedContext, bool(bool));
- MOCK_METHOD5(drawLayers,
+ MOCK_METHOD6(drawLayers,
status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
- ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*));
+ ANativeWindowBuffer*, const bool, base::unique_fd&&, base::unique_fd*));
};
} // namespace mock
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 8c93cf4..7acaecf 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -118,7 +118,7 @@
void invokeDraw(renderengine::DisplaySettings settings,
std::vector<renderengine::LayerSettings> layers, sp<GraphicBuffer> buffer) {
base::unique_fd fence;
- status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(),
+ status_t status = sRE->drawLayers(settings, layers, buffer->getNativeBuffer(), true,
base::unique_fd(), &fence);
sCurrentBuffer = buffer;
@@ -770,7 +770,7 @@
BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
layers.push_back(layer);
base::unique_fd fence;
- status_t status = sRE->drawLayers(settings, layers, nullptr, base::unique_fd(), &fence);
+ status_t status = sRE->drawLayers(settings, layers, nullptr, true, base::unique_fd(), &fence);
ASSERT_EQ(BAD_VALUE, status);
}
@@ -787,13 +787,33 @@
layer.alpha = 1.0;
layers.push_back(layer);
- status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(),
+ status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), true,
base::unique_fd(), nullptr);
sCurrentBuffer = mBuffer;
ASSERT_EQ(NO_ERROR, status);
expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
}
+TEST_F(RenderEngineTest, drawLayers_doesNotCacheFramebuffer) {
+ renderengine::DisplaySettings settings;
+ settings.physicalDisplay = fullscreenRect();
+ settings.clip = fullscreenRect();
+
+ std::vector<renderengine::LayerSettings> layers;
+ renderengine::LayerSettings layer;
+ layer.geometry.boundaries = fullscreenRect().toFloatRect();
+ BufferSourceVariant<ForceOpaqueBufferVariant>::fillColor(layer, 1.0f, 0.0f, 0.0f, this);
+ layer.alpha = 1.0;
+ layers.push_back(layer);
+
+ status_t status = sRE->drawLayers(settings, layers, mBuffer->getNativeBuffer(), false,
+ base::unique_fd(), nullptr);
+ sCurrentBuffer = mBuffer;
+ ASSERT_EQ(NO_ERROR, status);
+ ASSERT_FALSE(sRE->isFramebufferImageCachedForTesting(mBuffer->getId()));
+ expectBufferColor(fullscreenRect(), 255, 0, 0, 255);
+}
+
TEST_F(RenderEngineTest, drawLayers_fillRedBuffer_colorSource) {
fillRedBuffer<ColorSourceVariant>();
}
@@ -1003,4 +1023,18 @@
EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
}
+TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferWithNullBuffer) {
+ status_t result = sRE->cacheExternalTextureBuffer(nullptr);
+ ASSERT_EQ(BAD_VALUE, result);
+}
+
+TEST_F(RenderEngineTest, drawLayers_cacheExternalBufferCachesImages) {
+ sp<GraphicBuffer> buf = allocateSourceBuffer(1, 1);
+ uint64_t bufferId = buf->getId();
+ sRE->cacheExternalTextureBuffer(buf);
+ EXPECT_TRUE(sRE->isImageCachedForTesting(bufferId));
+ sRE->unbindExternalTextureBuffer(bufferId);
+ EXPECT_FALSE(sRE->isImageCachedForTesting(bufferId));
+}
+
} // namespace android
diff --git a/libs/ui/tests/BufferHubBuffer_test.cpp b/libs/ui/tests/BufferHubBuffer_test.cpp
index efc1a80..0c73a72 100644
--- a/libs/ui/tests/BufferHubBuffer_test.cpp
+++ b/libs/ui/tests/BufferHubBuffer_test.cpp
@@ -19,6 +19,7 @@
#include <errno.h>
#include <sys/epoll.h>
+#include <android/frameworks/bufferhub/1.0/IBufferHub.h>
#include <android/hardware_buffer.h>
#include <cutils/native_handle.h>
#include <gmock/gmock.h>
@@ -40,6 +41,7 @@
using ::android::BufferHubDefs::isClientPosted;
using ::android::BufferHubDefs::isClientReleased;
using ::android::BufferHubDefs::kMetadataHeaderSize;
+using ::android::frameworks::bufferhub::V1_0::IBufferHub;
using ::testing::IsNull;
using ::testing::NotNull;
@@ -54,7 +56,20 @@
class BufferHubBufferTest : public ::testing::Test {
protected:
- void SetUp() override { android::hardware::ProcessState::self()->startThreadPool(); }
+ void SetUp() override {
+ android::hardware::ProcessState::self()->startThreadPool();
+
+ if (!BufferHubServiceRunning()) {
+ // TODO(b/112940221): Enforce the test cross all devices once BufferHub lands in Android
+ // R for all Android varieties.
+ GTEST_SKIP() << "Skip test as the BufferHub service is not running.";
+ }
+ }
+
+ bool BufferHubServiceRunning() {
+ sp<IBufferHub> bufferhub = IBufferHub::getService();
+ return bufferhub.get() != nullptr;
+ }
};
bool cmpAHardwareBufferDesc(const AHardwareBuffer_Desc& desc, const AHardwareBuffer_Desc& other) {
@@ -67,6 +82,13 @@
protected:
void SetUp() override {
BufferHubBufferTest::SetUp();
+
+ if (IsSkipped()) {
+ // If the base class' SetUp() stated the test should be skipped, we should short
+ // circuit this sub-class' logic.
+ return;
+ }
+
CreateTwoClientsOfABuffer();
}
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index fa92830..6d202ae 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -59,9 +59,6 @@
"libbufferhub_headers",
"libnativebase_headers",
],
-
- // TODO(b/117568153): Temporarily opt out using libcrt.
- no_libcrt: true,
}
cc_test {
@@ -70,7 +67,4 @@
shared_libs: sharedLibraries,
header_libs: headerLibraries,
name: "buffer_hub-test",
-
- // TODO(b/117568153): Temporarily opt out using libcrt.
- no_libcrt: true,
}
diff --git a/libs/vr/libbufferhubqueue/Android.bp b/libs/vr/libbufferhubqueue/Android.bp
index 20894e3..9f72c05 100644
--- a/libs/vr/libbufferhubqueue/Android.bp
+++ b/libs/vr/libbufferhubqueue/Android.bp
@@ -59,9 +59,6 @@
static_libs: staticLibraries,
shared_libs: sharedLibraries,
header_libs: headerLibraries,
-
- // TODO(b/117568153): Temporarily opt out using libcrt.
- no_libcrt: true,
}
subdirs = ["benchmarks", "tests"]
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 357dffe..3260447 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -49,9 +49,6 @@
"-g",
],
name: "dvr_api-test",
-
- // TODO(b/117568153): Temporarily opt out using libcrt.
- no_libcrt: true,
}
cc_test {
diff --git a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
index ed72577..7b3717e 100644
--- a/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_display_manager-test.cpp
@@ -28,6 +28,8 @@
namespace {
+using ::testing::Test;
+
DvrSurfaceAttribute MakeAttribute(DvrSurfaceAttributeKey key, nullptr_t) {
DvrSurfaceAttribute attribute;
attribute.key = key;
@@ -141,6 +143,23 @@
return {UniqueDvrWriteBufferQueue(queue)};
}
+Status<std::vector<uint8_t>> GetConfigData(int config_type) {
+ uint8_t* data = nullptr;
+ size_t data_size = 0;
+ int error = dvrConfigurationDataGet(config_type, &data, &data_size);
+ if (error < 0) {
+ return ErrorStatus(-error);
+ }
+
+ if (!data || data_size == 0) {
+ return ErrorStatus(EINVAL);
+ }
+ std::vector<uint8_t> data_result(data, data + data_size);
+ dvrConfigurationDataDestroy(data);
+ std::string s(data, data + data_size);
+ return {std::move(data_result)};
+}
+
class TestDisplayManager {
public:
TestDisplayManager(UniqueDvrDisplayManager display_manager,
@@ -275,23 +294,6 @@
return {std::move(queue_ids)};
}
- Status<std::vector<uint8_t>> GetConfigData(int config_type) {
- uint8_t* data = nullptr;
- size_t data_size = 0;
- int error = dvrConfigurationDataGet(config_type, &data, &data_size);
- if (error < 0) {
- return ErrorStatus(-error);
- }
-
- if (!data || data_size == 0) {
- return ErrorStatus(EINVAL);
- }
- std::vector<uint8_t> data_result(data, data + data_size);
- dvrConfigurationDataDestroy(data);
- std::string s(data, data + data_size);
- return {std::move(data_result)};
- }
-
private:
UniqueDvrDisplayManager display_manager_;
UniqueDvrSurfaceState surface_state_;
@@ -303,9 +305,17 @@
void operator=(const TestDisplayManager&) = delete;
};
-class DvrDisplayManagerTest : public ::testing::Test {
+class DvrDisplayManagerTest : public Test {
protected:
void SetUp() override {
+ // dvr display manager test doesn't apply to standalone vr devices because
+ // tests cannot create display manager client on these devices.
+ if (property_get_bool("ro.boot.vr", false)) {
+ GTEST_SKIP()
+ << "All tests in DvrDisplayManagerTest test case are skipped "
+ "because the device boot to VR.";
+ }
+
int ret;
DvrDisplayManager* display_manager;
DvrSurfaceState* surface_state;
@@ -429,7 +439,7 @@
#if 0
// Verify utility predicate/macro functionality. This section is commented out
// because it is designed to fail in some cases to validate the helpers.
-TEST_F(DvrDisplayManagerTest, ExpectVoid) {
+TEST_F(Test, ExpectVoid) {
Status<void> status_error{ErrorStatus{EINVAL}};
Status<void> status_ok{};
@@ -444,7 +454,7 @@
EXPECT_STATUS_ERROR_VALUE(ENOMEM, status_ok);
}
-TEST_F(DvrDisplayManagerTest, ExpectInt) {
+TEST_F(Test, ExpectInt) {
Status<int> status_error{ErrorStatus{EINVAL}};
Status<int> status_ok{10};
@@ -480,11 +490,6 @@
#endif
TEST_F(DvrDisplayManagerTest, SurfaceCreateEvent) {
- // This test doesn't apply to standalone vr devices.
- if (property_get_bool("ro.boot.vr", false)) {
- return;
- }
-
// Get surface state and verify there are no surfaces.
ASSERT_STATUS_OK(manager_->UpdateSurfaceState());
ASSERT_STATUS_EQ(0u, manager_->GetSurfaceCount());
@@ -524,11 +529,6 @@
}
TEST_F(DvrDisplayManagerTest, SurfaceAttributeEvent) {
- // This test doesn't apply to standalone vr devices.
- if (property_get_bool("ro.boot.vr", false)) {
- return;
- }
-
// Get surface state and verify there are no surfaces.
ASSERT_STATUS_OK(manager_->UpdateSurfaceState());
ASSERT_STATUS_EQ(0u, manager_->GetSurfaceCount());
@@ -768,11 +768,6 @@
}
TEST_F(DvrDisplayManagerTest, SurfaceQueueEvent) {
- // This test doesn't apply to standalone vr devices.
- if (property_get_bool("ro.boot.vr", false)) {
- return;
- }
-
// Create an application surface.
auto surface_status = CreateApplicationSurface();
ASSERT_STATUS_OK(surface_status);
@@ -841,11 +836,6 @@
}
TEST_F(DvrDisplayManagerTest, MultiLayerBufferQueue) {
- // This test doesn't apply to standalone vr devices.
- if (property_get_bool("ro.boot.vr", false)) {
- return;
- }
-
// Create an application surface.
auto surface_status = CreateApplicationSurface();
ASSERT_STATUS_OK(surface_status);
@@ -884,16 +874,17 @@
dvrWriteBufferDestroy(buffer);
}
-TEST_F(DvrDisplayManagerTest, ConfigurationData) {
- // TODO(hendrikw): Move this out of the display manager tests.
- auto data1 = manager_->GetConfigData(-1);
+TEST_F(Test, ConfigurationData) {
+ // TODO(hendrikw): Move this test and GetConfigData helper function out of the
+ // display manager tests.
+ auto data1 = GetConfigData(-1);
ASSERT_STATUS_ERROR(data1);
const char kDvrLensMetricsProperty[] = "ro.dvr.lens_metrics";
// This should be run on devices with and without built in metrics.
bool has_metric = !base::GetProperty(kDvrLensMetricsProperty, "").empty();
- auto data2 = manager_->GetConfigData(DVR_CONFIGURATION_DATA_LENS_METRICS);
+ auto data2 = GetConfigData(DVR_CONFIGURATION_DATA_LENS_METRICS);
if (has_metric) {
ASSERT_STATUS_OK(data2);
ASSERT_NE(0u, data2.get().size());
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
index c884cb3..410e234 100644
--- a/libs/vr/libvrflinger/tests/Android.bp
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -33,7 +33,4 @@
"-Werror",
],
name: "vrflinger_test",
-
- // TODO(b/117568153): Temporarily opt out using libcrt.
- no_libcrt: true,
}
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index abdecd9..2549d9b 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -2141,7 +2141,7 @@
return; // skip the inconsistent event
}
- dispatchPointerDownOutsideFocusIfNecessary(motionEntry->source,
+ dispatchPointerDownOutsideFocus(motionEntry->source,
dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken());
break;
@@ -2159,10 +2159,11 @@
}
-void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action,
+void InputDispatcher::dispatchPointerDownOutsideFocus(uint32_t source, int32_t action,
const sp<IBinder>& newToken) {
int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
- if (source != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) {
+ uint32_t maskedSource = source & AINPUT_SOURCE_CLASS_MASK;
+ if (maskedSource != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) {
return;
}
@@ -2181,7 +2182,9 @@
return;
}
- // Dispatch onPointerDownOutsideFocus to the policy.
+ CommandEntry* commandEntry = postCommandLocked(
+ & InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible);
+ commandEntry->newToken = newToken;
}
void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -4192,6 +4195,12 @@
entry->release();
}
+void InputDispatcher::doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry) {
+ mLock.unlock();
+ mPolicy->onPointerDownOutsideFocus(commandEntry->newToken);
+ mLock.lock();
+}
+
void InputDispatcher::doDispatchCycleFinishedLockedInterruptible(
CommandEntry* commandEntry) {
sp<Connection> connection = commandEntry->connection;
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 65d6d67..753b748 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -274,6 +274,13 @@
*/
virtual bool checkInjectEventsPermissionNonReentrant(
int32_t injectorPid, int32_t injectorUid) = 0;
+
+ /* Notifies the policy that a pointer down event has occurred outside the current focused
+ * window.
+ *
+ * The touchedToken passed as an argument is the window that received the input event.
+ */
+ virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0;
};
@@ -1207,7 +1214,7 @@
void releaseDispatchEntry(DispatchEntry* dispatchEntry);
static int handleReceiveCallback(int fd, int events, void* data);
// The action sent should only be of type AMOTION_EVENT_*
- void dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action,
+ void dispatchPointerDownOutsideFocus(uint32_t source, int32_t action,
const sp<IBinder>& newToken) REQUIRES(mLock);
void synthesizeCancelationEventsForAllConnectionsLocked(
@@ -1268,6 +1275,8 @@
DispatchEntry* dispatchEntry, MotionEntry* motionEntry, bool handled) REQUIRES(mLock);
void doPokeUserActivityLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
void initializeKeyEvent(KeyEvent* event, const KeyEntry* entry);
+ void doOnPointerDownOutsideFocusLockedInterruptible(CommandEntry* commandEntry)
+ REQUIRES(mLock);
// Statistics gathering.
void updateDispatchStatistics(nsecs_t currentTime, const EventEntry* entry,
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 38a8c6f..9fe6481 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -52,6 +52,7 @@
mTime = -1;
mAction = -1;
mDisplayId = -1;
+ mOnPointerDownToken.clear();
}
void assertFilterInputEventWasCalledWithExpectedArgs(const NotifyMotionArgs* args) {
@@ -87,11 +88,18 @@
<< "Expected filterInputEvent() to not have been called.";
}
+ void assertOnPointerDownEquals(const sp<IBinder>& touchedToken) {
+ ASSERT_EQ(mOnPointerDownToken, touchedToken)
+ << "Expected token from onPointerDownOutsideFocus was not matched";
+ reset();
+ }
+
private:
bool mInputEventFiltered;
nsecs_t mTime;
int32_t mAction;
int32_t mDisplayId;
+ sp<IBinder> mOnPointerDownToken;
virtual void notifyConfigurationChanged(nsecs_t) {
}
@@ -161,11 +169,16 @@
return false;
}
+ virtual void onPointerDownOutsideFocus(const sp<IBinder>& newToken) {
+ mOnPointerDownToken = newToken;
+ }
+
void reset() {
mInputEventFiltered = false;
mTime = -1;
mAction = -1;
mDisplayId = -1;
+ mOnPointerDownToken.clear();
}
};
@@ -431,7 +444,7 @@
FakeWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle,
const sp<InputDispatcher>& dispatcher, const std::string name, int32_t displayId) :
FakeInputReceiver(dispatcher, name, displayId),
- mFocused(false) {
+ mFocused(false), mFrame(Rect(0, 0, WIDTH, HEIGHT)), mLayoutParamFlags(0) {
mServerChannel->setToken(new BBinder());
mDispatcher->registerInputChannel(mServerChannel, displayId);
@@ -442,15 +455,15 @@
virtual bool updateInfo() {
mInfo.token = mServerChannel ? mServerChannel->getToken() : nullptr;
mInfo.name = mName;
- mInfo.layoutParamsFlags = 0;
+ mInfo.layoutParamsFlags = mLayoutParamFlags;
mInfo.layoutParamsType = InputWindowInfo::TYPE_APPLICATION;
mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
- mInfo.frameLeft = 0;
- mInfo.frameTop = 0;
- mInfo.frameRight = WIDTH;
- mInfo.frameBottom = HEIGHT;
+ mInfo.frameLeft = mFrame.left;
+ mInfo.frameTop = mFrame.top;
+ mInfo.frameRight = mFrame.right;
+ mInfo.frameBottom = mFrame.bottom;
mInfo.globalScaleFactor = 1.0;
- mInfo.addTouchableRegion(Rect(0, 0, WIDTH, HEIGHT));
+ mInfo.addTouchableRegion(mFrame);
mInfo.visible = true;
mInfo.canReceiveKeys = true;
mInfo.hasFocus = mFocused;
@@ -469,6 +482,14 @@
mFocused = true;
}
+ void setFrame(const Rect& frame) {
+ mFrame.set(frame);
+ }
+
+ void setLayoutParamFlags(int32_t flags) {
+ mLayoutParamFlags = flags;
+ }
+
void releaseChannel() {
mServerChannel.clear();
InputWindowHandle::releaseChannel();
@@ -479,6 +500,8 @@
}
bool mFocused;
+ Rect mFrame;
+ int32_t mLayoutParamFlags;
};
static int32_t injectKeyDown(const sp<InputDispatcher>& dispatcher,
@@ -499,7 +522,7 @@
}
static int32_t injectMotionDown(const sp<InputDispatcher>& dispatcher, int32_t source,
- int32_t displayId) {
+ int32_t displayId, int32_t x = 100, int32_t y = 200) {
MotionEvent event;
PointerProperties pointerProperties[1];
PointerCoords pointerCoords[1];
@@ -509,13 +532,13 @@
pointerProperties[0].toolType = AMOTION_EVENT_TOOL_TYPE_FINGER;
pointerCoords[0].clear();
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 100);
- pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 200);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, x);
+ pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, y);
nsecs_t currentTime = systemTime(SYSTEM_TIME_MONOTONIC);
// Define a valid motion down event.
event.initialize(DEVICE_ID, source, displayId,
- AMOTION_EVENT_ACTION_DOWN, /* actionButton */0, /* flags */ 0, /* edgeFlags */ 0,
+ AMOTION_EVENT_ACTION_DOWN, /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0,
AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
/* xOffset */ 0, /* yOffset */ 0, /* xPrecision */ 0,
/* yPrecision */ 0, currentTime, currentTime, /*pointerCount*/ 1, pointerProperties,
@@ -908,4 +931,98 @@
testNotifyKey(/*expectToBeFiltered*/ false);
}
+class InputDispatcherOnPointerDownOutsideFocus : public InputDispatcherTest {
+ virtual void SetUp() {
+ InputDispatcherTest::SetUp();
+
+ sp<FakeApplicationHandle> application = new FakeApplicationHandle();
+ mUnfocusedWindow = new FakeWindowHandle(application, mDispatcher, "Top",
+ ADISPLAY_ID_DEFAULT);
+ mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
+ // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
+ // window.
+ mUnfocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+
+ mWindowFocused = new FakeWindowHandle(application, mDispatcher, "Second",
+ ADISPLAY_ID_DEFAULT);
+ mWindowFocused->setFrame(Rect(50, 50, 100, 100));
+ mWindowFocused->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL);
+ mWindowFocusedTouchPoint = 60;
+
+ // Set focused application.
+ mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+ mWindowFocused->setFocus();
+
+ // Expect one focus window exist in display.
+ std::vector<sp<InputWindowHandle>> inputWindowHandles;
+ inputWindowHandles.push_back(mUnfocusedWindow);
+ inputWindowHandles.push_back(mWindowFocused);
+ mDispatcher->setInputWindows(inputWindowHandles, ADISPLAY_ID_DEFAULT);
+ }
+
+ virtual void TearDown() {
+ InputDispatcherTest::TearDown();
+
+ mUnfocusedWindow.clear();
+ mWindowFocused.clear();
+ }
+
+protected:
+ sp<FakeWindowHandle> mUnfocusedWindow;
+ sp<FakeWindowHandle> mWindowFocused;
+ int32_t mWindowFocusedTouchPoint;
+};
+
+// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
+// DOWN on the window that doesn't have focus. Ensure the window that didn't have focus received
+// the onPointerDownOutsideFocus callback.
+TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_Success) {
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, 20, 20))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ // Call monitor to wait for the command queue to get flushed.
+ mDispatcher->monitor();
+
+ mFakePolicy->assertOnPointerDownEquals(mUnfocusedWindow->getToken());
+}
+
+// Have two windows, one with focus. Inject MotionEvent with source TRACKBALL and action
+// DOWN on the window that doesn't have focus. Ensure no window received the
+// onPointerDownOutsideFocus callback.
+TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonPointerSource) {
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TRACKBALL, ADISPLAY_ID_DEFAULT, 20, 20))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ // Call monitor to wait for the command queue to get flushed.
+ mDispatcher->monitor();
+
+ mFakePolicy->assertOnPointerDownEquals(nullptr);
+}
+
+// Have two windows, one with focus. Inject KeyEvent with action DOWN on the window that doesn't
+// have focus. Ensure no window received the onPointerDownOutsideFocus callback.
+TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_NonMotionFailure) {
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectKeyDown(mDispatcher, ADISPLAY_ID_DEFAULT))
+ << "Inject key event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ // Call monitor to wait for the command queue to get flushed.
+ mDispatcher->monitor();
+
+ mFakePolicy->assertOnPointerDownEquals(nullptr);
+}
+
+// Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
+// DOWN on the window that already has focus. Ensure no window received the
+// onPointerDownOutsideFocus callback.
+TEST_F(InputDispatcherOnPointerDownOutsideFocus,
+ OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
+ ASSERT_EQ(INPUT_EVENT_INJECTION_SUCCEEDED, injectMotionDown(mDispatcher,
+ AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, mWindowFocusedTouchPoint,
+ mWindowFocusedTouchPoint))
+ << "Inject motion event should return INPUT_EVENT_INJECTION_SUCCEEDED";
+ // Call monitor to wait for the command queue to get flushed.
+ mDispatcher->monitor();
+
+ mFakePolicy->assertOnPointerDownEquals(nullptr);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index c3324af..52c68df 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -47,7 +47,7 @@
"libhwbinder",
"liblayers_proto",
"liblog",
- "libnativewindow",
+ "libnativewindow",
"libpdx_default_transport",
"libprocessgroup",
"libprotobuf-cpp-lite",
@@ -56,7 +56,7 @@
"libui",
"libinput",
"libutils",
- "libSurfaceFlingerProperties",
+ "libSurfaceFlingerProp",
],
static_libs: [
"libcompositionengine",
@@ -222,7 +222,7 @@
srcs: [":surfaceflinger_binary_sources"],
shared_libs: [
"libsurfaceflinger",
- "libSurfaceFlingerProperties",
+ "libSurfaceFlingerProp",
],
}
@@ -233,10 +233,9 @@
]
cc_library_shared {
- name: "libSurfaceFlingerProperties",
+ name: "libSurfaceFlingerProp",
srcs: [
"SurfaceFlingerProperties.cpp",
- "sysprop/*.sysprop",
],
shared_libs: [
"android.hardware.configstore-utils",
@@ -248,6 +247,10 @@
"libhwbinder",
"libui",
"libutils",
+ "liblog",
+ ],
+ static_libs: [
+ "SurfaceFlingerProperties",
],
export_shared_lib_headers: [
"android.hardware.graphics.common@1.2",
@@ -255,4 +258,7 @@
"libhidltransport",
"libhwbinder",
],
+ export_static_lib_headers: [
+ "SurfaceFlingerProperties",
+ ],
}
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index f2d4c51..fc98dc8 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -217,7 +217,11 @@
// If item->mGraphicBuffer is not null, this buffer has not been acquired
// before, so we need to clean up old references.
if (item->mGraphicBuffer != nullptr) {
- mImages[item->mSlot] = std::make_shared<Image>(item->mGraphicBuffer, mRE);
+ std::lock_guard<std::mutex> lock(mImagesMutex);
+ if (mImages[item->mSlot] == nullptr || mImages[item->mSlot]->graphicBuffer() == nullptr ||
+ mImages[item->mSlot]->graphicBuffer()->getId() != item->mGraphicBuffer->getId()) {
+ mImages[item->mSlot] = std::make_shared<Image>(item->mGraphicBuffer, mRE);
+ }
}
return NO_ERROR;
@@ -238,7 +242,12 @@
// Hang onto the pointer so that it isn't freed in the call to
// releaseBufferLocked() if we're in shared buffer mode and both buffers are
// the same.
- std::shared_ptr<Image> nextTextureBuffer = mImages[slot];
+
+ std::shared_ptr<Image> nextTextureBuffer;
+ {
+ std::lock_guard<std::mutex> lock(mImagesMutex);
+ nextTextureBuffer = mImages[slot];
+ }
// release old buffer
if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
@@ -436,6 +445,7 @@
void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
+ std::lock_guard<std::mutex> lock(mImagesMutex);
if (slotIndex == mCurrentTexture) {
mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
}
@@ -468,6 +478,23 @@
}
}
+void BufferLayerConsumer::onBufferAllocated(const BufferItem& item) {
+ if (item.mGraphicBuffer != nullptr) {
+ std::shared_ptr<Image> image = std::make_shared<Image>(item.mGraphicBuffer, mRE);
+ std::shared_ptr<Image> oldImage;
+ {
+ std::lock_guard<std::mutex> lock(mImagesMutex);
+ oldImage = mImages[item.mSlot];
+ if (oldImage == nullptr || oldImage->graphicBuffer() == nullptr ||
+ oldImage->graphicBuffer()->getId() != item.mGraphicBuffer->getId()) {
+ mImages[item.mSlot] = std::make_shared<Image>(item.mGraphicBuffer, mRE);
+ }
+ image = mImages[item.mSlot];
+ }
+ mRE.cacheExternalTextureBuffer(image->graphicBuffer());
+ }
+}
+
void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) {
sp<Layer> l = mLayer.promote();
@@ -480,6 +507,7 @@
BLC_LOGV("abandonLocked");
mCurrentTextureBuffer = nullptr;
for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+ std::lock_guard<std::mutex> lock(mImagesMutex);
mImages[i] = nullptr;
}
ConsumerBase::abandonLocked();
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index f4ca846..0f0655d 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -17,6 +17,7 @@
#ifndef ANDROID_BUFFERLAYERCONSUMER_H
#define ANDROID_BUFFERLAYERCONSUMER_H
+#include <android-base/thread_annotations.h>
#include <gui/BufferQueueDefs.h>
#include <gui/ConsumerBase.h>
#include <gui/HdrMetadata.h>
@@ -179,7 +180,7 @@
protected:
// abandonLocked overrides the ConsumerBase method to clear
// mCurrentTextureImage in addition to the ConsumerBase behavior.
- virtual void abandonLocked();
+ virtual void abandonLocked() EXCLUDES(mImagesMutex);
// dumpLocked overrides the ConsumerBase method to dump BufferLayerConsumer-
// specific info in addition to the ConsumerBase behavior.
@@ -187,7 +188,8 @@
// See ConsumerBase::acquireBufferLocked
virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
- uint64_t maxFrameNumber = 0) override;
+ uint64_t maxFrameNumber = 0) override
+ EXCLUDES(mImagesMutex);
bool canUseImageCrop(const Rect& crop) const;
@@ -206,7 +208,8 @@
// completion of the method will instead be returned to the caller, so that
// it may call releaseBufferLocked itself later.
status_t updateAndReleaseLocked(const BufferItem& item,
- PendingRelease* pendingRelease = nullptr);
+ PendingRelease* pendingRelease = nullptr)
+ EXCLUDES(mImagesMutex);
// Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.
// If the bind succeeds, this calls doFenceWait.
@@ -234,10 +237,11 @@
// that slot. Otherwise it has no effect.
//
// This method must be called with mMutex locked.
- virtual void freeBufferLocked(int slotIndex);
+ virtual void freeBufferLocked(int slotIndex) EXCLUDES(mImagesMutex);
// IConsumerListener interface
void onDisconnect() override;
+ void onBufferAllocated(const BufferItem& item) override EXCLUDES(mImagesMutex);
void onSidebandStreamChanged() override;
void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
FrameEventHistoryDelta* outDelta) override;
@@ -344,7 +348,12 @@
int mCurrentTexture;
// Shadow buffer cache for cleaning up renderengine references.
- std::shared_ptr<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
+ std::shared_ptr<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS] GUARDED_BY(mImagesMutex);
+
+ // Separate mutex guarding the shadow buffer cache.
+ // mImagesMutex can be manipulated with binder threads (e.g. onBuffersAllocated)
+ // which is contentious enough that we can't just use mMutex.
+ mutable std::mutex mImagesMutex;
// A release that is pending on the receipt of a new release fence from
// presentDisplay
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index d3b36fe..b623991 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -23,6 +23,7 @@
#include "BufferQueueLayer.h"
#include "LayerRejecter.h"
+#include "SurfaceInterceptor.h"
#include "TimeStats/TimeStats.h"
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index ad08a92..7927fa9 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -42,32 +42,4 @@
void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
const Rect&, int32_t, const ui::Dataspace) {}
-Layer::RoundedCornerState ContainerLayer::getRoundedCornerStateInternal(
- const FloatRect bounds) const {
- const auto& p = mDrawingParent.promote();
- if (p != nullptr) {
- RoundedCornerState parentState = p->getRoundedCornerStateInternal(bounds);
- if (parentState.radius > 0) {
- ui::Transform t = getActiveTransform(getDrawingState());
- t = t.inverse();
- parentState.cropRect = t.transform(parentState.cropRect);
- // The rounded corners shader only accepts 1 corner radius for performance reasons,
- // but a transform matrix can define horizontal and vertical scales.
- // Let's take the average between both of them and pass into the shader, practically we
- // never do this type of transformation on windows anyway.
- parentState.radius *= (t[0][0] + t[1][1]) / 2.0f;
- return parentState;
- }
- }
- const float radius = getDrawingState().cornerRadius;
- if (radius > 0) {
- const Rect crop = getCrop(getDrawingState());
- if (!crop.isEmpty()) {
- return RoundedCornerState(bounds.intersect(crop.toFloatRect()), radius);
- }
- return RoundedCornerState(bounds, radius);
- }
- return RoundedCornerState();
-}
-
} // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index cd8e722..7222a3e 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -40,7 +40,6 @@
bool isCreatedFromMainThread() const override { return true; }
bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
- Layer::RoundedCornerState getRoundedCornerStateInternal(const FloatRect bounds) const override;
protected:
bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 62073b6..12a94a7 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -26,7 +26,6 @@
#include <ui/Fence.h>
#include <ui/FloatRect.h>
#include <ui/GraphicBuffer.h>
-#include <ui/Region.h>
#include <android/configuration.h>
@@ -826,6 +825,11 @@
Error Layer::setBuffer(uint32_t slot, const sp<GraphicBuffer>& buffer,
const sp<Fence>& acquireFence)
{
+ if (buffer == nullptr && mBufferSlot == slot) {
+ return Error::None;
+ }
+ mBufferSlot = slot;
+
int32_t fenceFd = acquireFence->dup();
auto intError = mComposer.setLayerBuffer(mDisplayId, mId, slot, buffer,
fenceFd);
@@ -834,6 +838,12 @@
Error Layer::setSurfaceDamage(const Region& damage)
{
+ if (damage.isRect() && mDamageRegion.isRect() &&
+ (damage.getBounds() == mDamageRegion.getBounds())) {
+ return Error::None;
+ }
+ mDamageRegion = damage;
+
// We encode default full-screen damage as INVALID_RECT upstream, but as 0
// rects for HWC
Hwc2::Error intError = Hwc2::Error::NONE;
@@ -988,6 +998,12 @@
Error Layer::setVisibleRegion(const Region& region)
{
+ if (region.isRect() && mVisibleRegion.isRect() &&
+ (region.getBounds() == mVisibleRegion.getBounds())) {
+ return Error::None;
+ }
+ mVisibleRegion = region;
+
size_t rectCount = 0;
auto rectArray = region.getArray(&rectCount);
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index 4209e45..e0a5ef1 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -27,6 +27,7 @@
#include <math/mat4.h>
#include <ui/GraphicTypes.h>
#include <ui/HdrCapabilities.h>
+#include <ui/Region.h>
#include <utils/Log.h>
#include <utils/StrongPointer.h>
#include <utils/Timers.h>
@@ -42,8 +43,6 @@
class Fence;
class FloatRect;
class GraphicBuffer;
- class Rect;
- class Region;
namespace Hwc2 {
class Composer;
}
@@ -438,9 +437,15 @@
hwc2_display_t mDisplayId;
hwc2_layer_t mId;
+
+ // Cached HWC2 data, to ensure the same commands aren't sent to the HWC
+ // multiple times.
+ android::Region mVisibleRegion = android::Region::INVALID_REGION;
+ android::Region mDamageRegion = android::Region::INVALID_REGION;
android::ui::Dataspace mDataSpace = android::ui::Dataspace::UNKNOWN;
android::HdrMetadata mHdrMetadata;
android::mat4 mColorMatrix;
+ uint32_t mBufferSlot;
};
} // namespace impl
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 73f27e4..7965245 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1788,13 +1788,9 @@
}
Layer::RoundedCornerState Layer::getRoundedCornerState() const {
- return getRoundedCornerStateInternal(mSourceBounds);
-}
-
-Layer::RoundedCornerState Layer::getRoundedCornerStateInternal(const FloatRect) const {
const auto& p = mDrawingParent.promote();
if (p != nullptr) {
- RoundedCornerState parentState = p->getRoundedCornerStateInternal(mSourceBounds);
+ RoundedCornerState parentState = p->getRoundedCornerState();
if (parentState.radius > 0) {
ui::Transform t = getActiveTransform(getDrawingState());
t = t.inverse();
@@ -1808,10 +1804,7 @@
}
}
const float radius = getDrawingState().cornerRadius;
- return radius > 0
- ? RoundedCornerState(mSourceBounds.intersect(getCrop(getDrawingState()).toFloatRect()),
- radius)
- : RoundedCornerState();
+ return radius > 0 ? RoundedCornerState(getBounds(), radius) : RoundedCornerState();
}
void Layer::commitChildList() {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index b9dc7ec..8348ce1 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -452,13 +452,13 @@
virtual void setPostTime(nsecs_t /*postTime*/) {}
virtual void setDesiredPresentTime(nsecs_t /*desiredPresentTime*/) {}
- virtual RoundedCornerState getRoundedCornerStateInternal(const FloatRect bounds) const;
protected:
virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
bool useIdentityTransform, Region& clearRegion,
const bool supportProtectedContent,
renderengine::LayerSettings& layer);
+
public:
/*
* compositionengine::LayerFE overrides
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index a2a6bd8..f72aef1 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -333,7 +333,6 @@
if (t < now) {
if (isShorterThanPeriod(now - eventListener.mLastCallbackTime)) {
eventListener.mLastEventTime = t;
- eventListener.mLastCallbackTime = now;
ALOGV("[%s] [%s] Skipping event due to model error", mName,
eventListener.mName);
continue;
diff --git a/services/surfaceflinger/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 78bf7c5..a760079 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -97,7 +97,7 @@
return event;
}
-DisplayEventReceiver::Event makeConfigChanged(uint32_t displayId, int32_t configId) {
+DisplayEventReceiver::Event makeConfigChanged(PhysicalDisplayId displayId, int32_t configId) {
DisplayEventReceiver::Event event;
event.header = {DisplayEventReceiver::DISPLAY_EVENT_CONFIG_CHANGED, displayId, systemTime()};
event.config.configId = configId;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f7e4afd..2ba55b5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -75,6 +75,7 @@
#include "BufferLayer.h"
#include "BufferQueueLayer.h"
#include "BufferStateLayer.h"
+#include "BufferStateLayerCache.h"
#include "Client.h"
#include "ColorLayer.h"
#include "Colorizer.h"
@@ -95,12 +96,14 @@
#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/VirtualDisplaySurface.h"
#include "Effects/Daltonizer.h"
+#include "RegionSamplingThread.h"
#include "Scheduler/DispSync.h"
#include "Scheduler/DispSyncSource.h"
#include "Scheduler/EventControlThread.h"
#include "Scheduler/EventThread.h"
#include "Scheduler/InjectVSyncSource.h"
#include "Scheduler/MessageQueue.h"
+#include "Scheduler/PhaseOffsets.h"
#include "Scheduler/Scheduler.h"
#include "TimeStats/TimeStats.h"
@@ -266,48 +269,17 @@
}
}
-SurfaceFlingerBE::SurfaceFlingerBE()
- : mHwcServiceName(getHwcServiceName()),
- mFrameBuckets(),
- mTotalTime(0),
- mLastSwapTime(0),
- mComposerSequenceId(0) {
-}
+SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {}
-SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory,
- SurfaceFlinger::SkipInitializationTag)
- : BnSurfaceComposer(),
- mFactory(factory),
- mTransactionPending(false),
- mAnimTransactionPending(false),
- mLayersRemoved(false),
- mLayersAdded(false),
- mBootTime(systemTime()),
- mPhaseOffsets{getFactory().createPhaseOffsets()},
- mVisibleRegionsDirty(false),
- mGeometryInvalid(false),
- mAnimCompositionPending(false),
- mBootStage(BootStage::BOOTLOADER),
- mDebugRegion(0),
- mDebugDisableHWC(0),
- mDebugDisableTransformHint(0),
- mDebugEnableProtectedContent(false),
- mDebugInTransaction(0),
- mLastTransactionTime(0),
- mForceFullDamage(false),
- mTracing(*this),
- mTimeStats(factory.createTimeStats()),
- mRefreshStartTime(0),
- mHasPoweredOff(false),
- mNumLayers(0),
- mVrFlingerRequestsDisplay(false),
- mMainThreadId(std::this_thread::get_id()),
- mCompositionEngine{getFactory().createCompositionEngine()} {
- mSetInputWindowsListener = new SetInputWindowsListener(this);
-}
+SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
+ : mFactory(factory),
+ mPhaseOffsets(mFactory.createPhaseOffsets()),
+ mInterceptor(mFactory.createSurfaceInterceptor(this)),
+ mTimeStats(mFactory.createTimeStats()),
+ mEventQueue(mFactory.createMessageQueue()),
+ mCompositionEngine(mFactory.createCompositionEngine()) {}
-SurfaceFlinger::SurfaceFlinger(surfaceflinger::Factory& factory)
- : SurfaceFlinger(factory, SkipInitialization) {
+SurfaceFlinger::SurfaceFlinger(Factory& factory) : SurfaceFlinger(factory, SkipInitialization) {
ALOGI("SurfaceFlinger is starting");
hasSyncFramework = running_without_sync_framework(true);
@@ -426,9 +398,7 @@
mEventQueue->init(this);
}
-SurfaceFlinger::~SurfaceFlinger()
-{
-}
+SurfaceFlinger::~SurfaceFlinger() = default;
void SurfaceFlinger::binderDied(const wp<IBinder>& /* who */)
{
@@ -666,6 +636,9 @@
renderengine::RenderEngine::USE_COLOR_MANAGEMENT : 0);
renderEngineFeature |= (useContextPriority ?
renderengine::RenderEngine::USE_HIGH_PRIORITY_CONTEXT : 0);
+ renderEngineFeature |=
+ (enable_protected_contents(false) ? renderengine::RenderEngine::ENABLE_PROTECTED_CONTEXT
+ : 0);
// TODO(b/77156734): We need to stop casting and use HAL types when possible.
// Sending maxFrameBufferAcquiredBuffers as the cache size is tightly tuned to single-display.
@@ -955,11 +928,6 @@
ALOGW("Attempt to set active config %d for virtual display", info.configId);
return;
}
- int currentDisplayPowerMode = display->getPowerMode();
- if (currentDisplayPowerMode != HWC_POWER_MODE_NORMAL) {
- // Don't change active config when in AoD.
- return;
- }
// Don't check against the current mode yet. Worst case we set the desired
// config twice. However event generation config might have changed so we need to update it
@@ -1708,22 +1676,22 @@
ATRACE_CALL();
uint32_t transactionFlags = peekTransactionFlags();
- // Apply any ready transactions in the queues if there are still transactions that have not been
- // applied, wake up during the next vsync period and check again
- bool transactionNeeded = false;
- if (!flushTransactionQueues()) {
- transactionNeeded = true;
+ bool flushedATransaction = flushTransactionQueues();
+
+ bool runHandleTransaction = transactionFlags &&
+ ((transactionFlags != eTransactionFlushNeeded) || flushedATransaction);
+
+ if (runHandleTransaction) {
+ handleTransaction(eTransactionMask);
+ } else {
+ getTransactionFlags(eTransactionFlushNeeded);
}
- if (transactionFlags) {
- handleTransaction(transactionFlags);
+ if (transactionFlushNeeded()) {
+ setTransactionFlags(eTransactionFlushNeeded);
}
- if (transactionNeeded) {
- setTransactionFlags(eTransactionNeeded);
- }
-
- return transactionFlags;
+ return runHandleTransaction;
}
void SurfaceFlinger::handleMessageRefresh() {
@@ -2421,8 +2389,6 @@
const auto& displayState = display->getState();
const auto displayId = display->getId();
- mPostFramebufferTime = systemTime();
-
if (displayState.isEnabled) {
if (displayId) {
getHwComposer().presentAndGetReleaseFences(*displayId);
@@ -2485,8 +2451,7 @@
State drawingState(mDrawingState);
Mutex::Autolock _l(mStateLock);
- const nsecs_t now = systemTime();
- mDebugInTransaction = now;
+ mDebugInTransaction = systemTime();
// Here we're guaranteed that some transaction flags are set
// so we can call handleTransactionLocked() unconditionally.
@@ -2498,7 +2463,6 @@
transactionFlags = getTransactionFlags(eTransactionMask);
handleTransactionLocked(transactionFlags);
- mLastTransactionTime = systemTime() - now;
mDebugInTransaction = 0;
invalidateHwcGeometry();
// here the transaction has been committed
@@ -2782,7 +2746,7 @@
* (perform the transaction for each of them if needed)
*/
- if (transactionFlags & eTraversalNeeded) {
+ if ((transactionFlags & eTraversalNeeded) || mTraversalNeededMainThread) {
mCurrentState.traverseInZOrder([&](Layer* layer) {
uint32_t trFlags = layer->getTransactionFlags(eTransactionNeeded);
if (!trFlags) return;
@@ -2795,6 +2759,7 @@
mInputInfoChanged = true;
}
});
+ mTraversalNeededMainThread = false;
}
/*
@@ -3330,6 +3295,7 @@
clientCompositionDisplay.clip = displayState.scissor;
const ui::Transform& displayTransform = displayState.transform;
clientCompositionDisplay.globalTransform = displayTransform.asMatrix4();
+ clientCompositionDisplay.orientation = displayState.orientation;
const auto* profile = display->getDisplayColorProfile();
Dataspace outputDataspace = Dataspace::UNKNOWN;
@@ -3440,7 +3406,8 @@
}
}
renderEngine.drawLayers(clientCompositionDisplay, clientCompositionLayers,
- buf->getNativeBuffer(), std::move(fd), readyFence);
+ buf->getNativeBuffer(), /*useFramebufferCache=*/true, std::move(fd),
+ readyFence);
if (expensiveRenderingExpected && displayId) {
mPowerAdvisor.setExpensiveRenderingExpected(*displayId, false);
}
@@ -3520,6 +3487,8 @@
bool SurfaceFlinger::flushTransactionQueues() {
Mutex::Autolock _l(mStateLock);
+ bool flushedATransaction = false;
+
auto it = mTransactionQueues.begin();
while (it != mTransactionQueues.end()) {
auto& [applyToken, transactionQueue] = *it;
@@ -3529,17 +3498,23 @@
[states, displays, flags, desiredPresentTime, uncacheBuffer, listenerCallbacks,
postTime, privileged] = transactionQueue.front();
if (!transactionIsReadyToBeApplied(desiredPresentTime, states)) {
+ setTransactionFlags(eTransactionFlushNeeded);
break;
}
applyTransactionState(states, displays, flags, mPendingInputWindowCommands,
desiredPresentTime, uncacheBuffer, listenerCallbacks, postTime,
privileged, /*isMainThread*/ true);
transactionQueue.pop();
+ flushedATransaction = true;
}
it = (transactionQueue.empty()) ? mTransactionQueues.erase(it) : std::next(it, 1);
}
- return mTransactionQueues.empty();
+ return flushedATransaction;
+}
+
+bool SurfaceFlinger::transactionFlushNeeded() {
+ return !mTransactionQueues.empty();
}
bool SurfaceFlinger::containsAnyInvalidClientState(const Vector<ComposerState>& states) {
@@ -3611,7 +3586,7 @@
mTransactionQueues[applyToken].emplace(states, displays, flags, desiredPresentTime,
uncacheBuffer, listenerCallbacks, postTime,
privileged);
- setTransactionFlags(eTransactionNeeded);
+ setTransactionFlags(eTransactionFlushNeeded);
return;
}
@@ -3649,18 +3624,22 @@
transactionFlags |= setDisplayStateLocked(display);
}
+ // In case the client has sent a Transaction that should receive callbacks but without any
+ // SurfaceControls that should be included in the callback, send the listener and callbackIds
+ // to the callback thread so it can send an empty callback
+ if (!listenerCallbacks.empty()) {
+ mTransactionCompletedThread.run();
+ }
+ for (const auto& [listener, callbackIds] : listenerCallbacks) {
+ mTransactionCompletedThread.addCallback(listener, callbackIds);
+ }
+
uint32_t clientStateFlags = 0;
for (const ComposerState& state : states) {
clientStateFlags |= setClientStateLocked(state, desiredPresentTime, listenerCallbacks,
postTime, privileged);
}
- // In case the client has sent a Transaction that should receive callbacks but without any
- // SurfaceControls that should be included in the callback, send the listener and callbackIds
- // to the callback thread so it can send an empty callback
- for (const auto& [listener, callbackIds] : listenerCallbacks) {
- mTransactionCompletedThread.addCallback(listener, callbackIds);
- }
// If the state doesn't require a traversal and there are callbacks, send them now
if (!(clientStateFlags & eTraversalNeeded)) {
mTransactionCompletedThread.sendCallbacks();
@@ -3682,6 +3661,13 @@
transactionFlags = eTransactionNeeded;
}
+ // If we are on the main thread, we are about to preform a traversal. Clear the traversal bit
+ // so we don't have to wake up again next frame to preform an uneeded traversal.
+ if (isMainThread && (transactionFlags & eTraversalNeeded)) {
+ transactionFlags = transactionFlags & (~eTraversalNeeded);
+ mTraversalNeededMainThread = true;
+ }
+
if (transactionFlags) {
if (mInterceptor->isEnabled()) {
mInterceptor->saveTransaction(states, mCurrentState.displays, displays, flags);
@@ -4010,7 +3996,6 @@
}
std::vector<sp<CallbackHandle>> callbackHandles;
if ((what & layer_state_t::eHasListenerCallbacksChanged) && (!listenerCallbacks.empty())) {
- mTransactionCompletedThread.run();
for (const auto& [listener, callbackIds] : listenerCallbacks) {
callbackHandles.emplace_back(new CallbackHandle(listener, callbackIds, s.surface));
}
@@ -5095,13 +5080,13 @@
}
case 1008: // toggle use of hw composer
n = data.readInt32();
- mDebugDisableHWC = n ? 1 : 0;
+ mDebugDisableHWC = n != 0;
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
case 1009: // toggle use of transform hint
n = data.readInt32();
- mDebugDisableTransformHint = n ? 1 : 0;
+ mDebugDisableTransformHint = n != 0;
invalidateHwcGeometry();
repaintEverything();
return NO_ERROR;
@@ -5183,7 +5168,7 @@
}
case 1017: {
n = data.readInt32();
- mForceFullDamage = static_cast<bool>(n);
+ mForceFullDamage = n != 0;
return NO_ERROR;
}
case 1018: { // Modify Choreographer's phase offset
@@ -5750,7 +5735,7 @@
base::unique_fd drawFence;
getRenderEngine().useProtectedContext(false);
getRenderEngine().drawLayers(clientCompositionDisplay, clientCompositionLayers, buffer,
- std::move(bufferFence), &drawFence);
+ /*useFramebufferCache=*/false, std::move(bufferFence), &drawFence);
*outSyncFd = drawFence.release();
}
@@ -5910,14 +5895,11 @@
return NO_ERROR;
}
-// ----------------------------------------------------------------------------
-
-void SetInputWindowsListener::onSetInputWindowsFinished() {
+void SurfaceFlinger::SetInputWindowsListener::onSetInputWindowsFinished() {
mFlinger->setInputWindowsFinished();
}
-}; // namespace android
-
+} // namespace android
#if defined(__gl_h_)
#error "don't include gl/gl.h in this file"
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 141af73..176c65d 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -14,8 +14,7 @@
* limitations under the License.
*/
-#ifndef ANDROID_SURFACE_FLINGER_H
-#define ANDROID_SURFACE_FLINGER_H
+#pragma once
#include <sys/types.h>
@@ -48,27 +47,18 @@
#include <utils/threads.h>
#include "AllowedDisplayConfigs.h"
-#include "Barrier.h"
-#include "BufferStateLayerCache.h"
#include "DisplayDevice.h"
#include "DisplayHardware/HWC2.h"
-#include "DisplayHardware/HWComposer.h"
#include "DisplayHardware/PowerAdvisor.h"
#include "Effects/Daltonizer.h"
#include "FrameTracker.h"
#include "LayerStats.h"
#include "LayerVector.h"
-#include "RegionSamplingThread.h"
-#include "Scheduler/DispSync.h"
-#include "Scheduler/EventThread.h"
-#include "Scheduler/MessageQueue.h"
-#include "Scheduler/PhaseOffsets.h"
#include "Scheduler/RefreshRateConfigs.h"
#include "Scheduler/RefreshRateStats.h"
#include "Scheduler/Scheduler.h"
#include "Scheduler/VSyncModulator.h"
#include "SurfaceFlingerFactory.h"
-#include "SurfaceInterceptor.h"
#include "SurfaceTracing.h"
#include "TransactionCompletedThread.h"
@@ -90,56 +80,37 @@
namespace android {
-using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
-
-// ---------------------------------------------------------------------------
-
class Client;
-class ColorLayer;
-class DisplayEventConnection;
-class EventControlThread;
class EventThread;
-class IGraphicBufferConsumer;
+class HWComposer;
class IGraphicBufferProducer;
class IInputFlinger;
class InjectVSyncSource;
class Layer;
+class MessageBase;
class RefreshRateOverlay;
-class Surface;
-class SurfaceFlingerBE;
+class RegionSamplingThread;
class TimeStats;
-class VSyncSource;
namespace compositionengine {
class DisplaySurface;
} // namespace compositionengine
-namespace impl {
-class EventThread;
-} // namespace impl
-
namespace renderengine {
class RenderEngine;
-}
-
-typedef std::function<void(const LayerVector::Visitor&)> TraverseLayersFunction;
+} // namespace renderengine
namespace dvr {
class VrFlinger;
} // namespace dvr
-namespace surfaceflinger {
-class NativeWindowSurface;
-} // namespace surfaceflinger
-
-// ---------------------------------------------------------------------------
-
enum {
- eTransactionNeeded = 0x01,
- eTraversalNeeded = 0x02,
+ eTransactionNeeded = 0x01,
+ eTraversalNeeded = 0x02,
eDisplayTransactionNeeded = 0x04,
eDisplayLayerStackChanged = 0x08,
- eTransactionMask = 0x0f,
+ eTransactionFlushNeeded = 0x10,
+ eTransactionMask = 0x1f,
};
enum class DisplayColorSetting : int32_t {
@@ -164,35 +135,28 @@
// Only accessed from the main thread.
struct CompositePresentTime {
- nsecs_t composite { -1 };
- std::shared_ptr<FenceTime> display { FenceTime::NO_FENCE };
+ nsecs_t composite = -1;
+ std::shared_ptr<FenceTime> display = FenceTime::NO_FENCE;
};
std::queue<CompositePresentTime> mCompositePresentTimes;
static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
- nsecs_t mFrameBuckets[NUM_BUCKETS];
- nsecs_t mTotalTime;
- std::atomic<nsecs_t> mLastSwapTime;
+ nsecs_t mFrameBuckets[NUM_BUCKETS] = {};
+ nsecs_t mTotalTime = 0;
+ std::atomic<nsecs_t> mLastSwapTime = 0;
// Double- vs. triple-buffering stats
struct BufferingStats {
- BufferingStats()
- : numSegments(0),
- totalTime(0),
- twoBufferTime(0),
- doubleBufferedTime(0),
- tripleBufferedTime(0) {}
-
- size_t numSegments;
- nsecs_t totalTime;
+ size_t numSegments = 0;
+ nsecs_t totalTime = 0;
// "Two buffer" means that a third buffer was never used, whereas
// "double-buffered" means that on average the segment only used two
// buffers (though it may have used a third for some part of the
// segment)
- nsecs_t twoBufferTime;
- nsecs_t doubleBufferedTime;
- nsecs_t tripleBufferedTime;
+ nsecs_t twoBufferTime = 0;
+ nsecs_t doubleBufferedTime = 0;
+ nsecs_t tripleBufferedTime = 0;
};
mutable Mutex mBufferingStatsMutex;
std::unordered_map<std::string, BufferingStats> mBufferingStats;
@@ -200,16 +164,7 @@
// The composer sequence id is a monotonically increasing integer that we
// use to differentiate callbacks from different hardware composer
// instances. Each hardware composer instance gets a different sequence id.
- int32_t mComposerSequenceId;
-};
-
-class SetInputWindowsListener : public BnSetInputWindowsListener {
-public:
- SetInputWindowsListener(const sp<SurfaceFlinger>& flinger) : mFlinger(flinger) {}
- void onSetInputWindowsFinished() override;
-
-private:
- const sp<SurfaceFlinger> mFlinger;
+ int32_t mComposerSequenceId = 0;
};
class SurfaceFlinger : public BnSurfaceComposer,
@@ -358,16 +313,12 @@
return mTransactionCompletedThread;
}
- void setInputWindowsFinished();
-
private:
- friend class Client;
- friend class DisplayEventConnection;
- friend class impl::EventThread;
- friend class Layer;
friend class BufferLayer;
friend class BufferQueueLayer;
friend class BufferStateLayer;
+ friend class Client;
+ friend class Layer;
friend class MonitoredProducer;
friend class RefreshRateOverlay;
friend class RegionSamplingThread;
@@ -532,6 +483,8 @@
void signalLayerUpdate();
void signalRefresh();
+ using RefreshRateType = scheduler::RefreshRateConfigs::RefreshRateType;
+
struct ActiveConfigInfo {
RefreshRateType type;
int configId;
@@ -587,6 +540,7 @@
void updateInputWindowInfo();
void commitInputWindowCommands() REQUIRES(mStateLock);
void executeInputWindowCommands();
+ void setInputWindowsFinished();
void updateCursorAsync();
/* handlePageFlip - latch a new buffer if available and compute the dirty
@@ -606,7 +560,10 @@
const std::vector<ListenerCallbacks>& listenerCallbacks,
const int64_t postTime, bool privileged, bool isMainThread = false)
REQUIRES(mStateLock);
+ // Returns true if at least one transaction was flushed
bool flushTransactionQueues();
+ // Returns true if there is at least one transaction that needs to be flushed
+ bool transactionFlushNeeded();
uint32_t getTransactionFlags(uint32_t flags);
uint32_t peekTransactionFlags();
// Can only be called from the main thread or with mStateLock held
@@ -673,6 +630,8 @@
void startBootAnim();
+ using TraverseLayersFunction = std::function<void(const LayerVector::Visitor&)>;
+
void renderScreenImplLocked(const RenderArea& renderArea, TraverseLayersFunction traverseLayers,
ANativeWindowBuffer* buffer, bool useIdentityTransform,
int* outSyncFd);
@@ -958,11 +917,12 @@
// access must be protected by mStateLock
mutable Mutex mStateLock;
State mCurrentState{LayerVector::StateSet::Current};
- std::atomic<int32_t> mTransactionFlags{0};
+ std::atomic<int32_t> mTransactionFlags = 0;
Condition mTransactionCV;
- bool mTransactionPending;
- bool mAnimTransactionPending;
- SortedVector< sp<Layer> > mLayersPendingRemoval;
+ bool mTransactionPending = false;
+ bool mAnimTransactionPending = false;
+ SortedVector<sp<Layer>> mLayersPendingRemoval;
+ bool mTraversalNeededMainThread = false;
// guards access to the mDrawing state if tracing is enabled.
mutable std::mutex mDrawingStateLock;
@@ -977,31 +937,30 @@
size_t mMaxGraphicBufferProducerListSize = MAX_LAYERS;
// protected by mStateLock (but we could use another lock)
- bool mLayersRemoved;
- bool mLayersAdded;
+ bool mLayersRemoved = false;
+ bool mLayersAdded = false;
- std::atomic<bool> mRepaintEverything{false};
+ std::atomic<bool> mRepaintEverything = false;
// constant members (no synchronization needed for access)
- nsecs_t mBootTime;
- bool mGpuToCpuSupported;
+ const nsecs_t mBootTime = systemTime();
+ bool mGpuToCpuSupported = false;
std::unique_ptr<EventThread> mInjectorEventThread;
std::unique_ptr<InjectVSyncSource> mVSyncInjector;
- std::unique_ptr<EventControlThread> mEventControlThread;
// Calculates correct offsets.
VSyncModulator mVsyncModulator;
// Keeps track of all available phase offsets for different refresh types.
- std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
+ const std::unique_ptr<scheduler::PhaseOffsets> mPhaseOffsets;
// Can only accessed from the main thread, these members
// don't need synchronization
State mDrawingState{LayerVector::StateSet::Drawing};
- bool mVisibleRegionsDirty;
+ bool mVisibleRegionsDirty = false;
// Set during transaction commit stage to track if the input info for a layer has changed.
- bool mInputInfoChanged{false};
- bool mGeometryInvalid;
- bool mAnimCompositionPending;
+ bool mInputInfoChanged = false;
+ bool mGeometryInvalid = false;
+ bool mAnimCompositionPending = false;
std::vector<sp<Layer>> mLayersWithQueuedFrames;
// Tracks layers that need to update a display's dirty region.
std::vector<sp<Layer>> mLayersPendingRefresh;
@@ -1018,7 +977,7 @@
BOOTANIMATION,
FINISHED,
};
- BootStage mBootStage;
+ BootStage mBootStage = BootStage::BOOTLOADER;
struct HotplugEvent {
hwc2_display_t hwcDisplayId;
@@ -1033,26 +992,23 @@
std::unordered_map<DisplayId, sp<IBinder>> mPhysicalDisplayTokens;
// don't use a lock for these, we don't care
- int mDebugRegion;
- int mDebugDisableHWC;
- int mDebugDisableTransformHint;
- bool mDebugEnableProtectedContent;
- volatile nsecs_t mDebugInSwapBuffers;
- volatile nsecs_t mDebugInTransaction;
- nsecs_t mLastTransactionTime;
- nsecs_t mPostFramebufferTime;
- bool mForceFullDamage;
+ int mDebugRegion = 0;
+ bool mDebugDisableHWC = false;
+ bool mDebugDisableTransformHint = false;
+ bool mDebugEnableProtectedContent = false;
+ volatile nsecs_t mDebugInTransaction = 0;
+ bool mForceFullDamage = false;
bool mPropagateBackpressure = true;
- std::unique_ptr<SurfaceInterceptor> mInterceptor{mFactory.createSurfaceInterceptor(this)};
- SurfaceTracing mTracing;
+ std::unique_ptr<SurfaceInterceptor> mInterceptor;
+ SurfaceTracing mTracing{*this};
bool mTracingEnabled = false;
bool mTracingEnabledChanged GUARDED_BY(mStateLock) = false;
LayerStats mLayerStats;
- std::shared_ptr<TimeStats> mTimeStats;
+ const std::shared_ptr<TimeStats> mTimeStats;
bool mUseHwcVirtualDisplays = false;
- std::atomic<uint32_t> mFrameMissedCount{0};
- std::atomic<uint32_t> mHwcFrameMissedCount{0};
- std::atomic<uint32_t> mGpuFrameMissedCount{0};
+ std::atomic<uint32_t> mFrameMissedCount = 0;
+ std::atomic<uint32_t> mHwcFrameMissedCount = 0;
+ std::atomic<uint32_t> mGpuFrameMissedCount = 0;
TransactionCompletedThread mTransactionCompletedThread;
@@ -1060,16 +1016,16 @@
bool mLayerTripleBufferingDisabled = false;
// these are thread safe
- mutable std::unique_ptr<MessageQueue> mEventQueue{mFactory.createMessageQueue()};
+ std::unique_ptr<MessageQueue> mEventQueue;
FrameTracker mAnimFrameTracker;
// protected by mDestroyedLayerLock;
mutable Mutex mDestroyedLayerLock;
Vector<Layer const *> mDestroyedLayers;
- nsecs_t mRefreshStartTime;
+ nsecs_t mRefreshStartTime = 0;
- std::atomic<bool> mRefreshPending{false};
+ std::atomic<bool> mRefreshPending = false;
// We maintain a pool of pre-generated texture names to hand out to avoid
// layer creation needing to run on the main thread (which it would
@@ -1113,21 +1069,21 @@
* Feature prototyping
*/
- bool mInjectVSyncs;
+ bool mInjectVSyncs = false;
// Static screen stats
- bool mHasPoweredOff;
+ bool mHasPoweredOff = false;
- size_t mNumLayers;
+ size_t mNumLayers = 0;
// Verify that transaction is being called by an approved process:
// either AID_GRAPHICS or AID_SYSTEM.
status_t CheckTransactCodeCredentials(uint32_t code);
std::unique_ptr<dvr::VrFlinger> mVrFlinger;
- std::atomic<bool> mVrFlingerRequestsDisplay;
+ std::atomic<bool> mVrFlingerRequestsDisplay = false;
static bool useVrFlinger;
- std::thread::id mMainThreadId;
+ std::thread::id mMainThreadId = std::this_thread::get_id();
DisplayColorSetting mDisplayColorSetting = DisplayColorSetting::ENHANCED;
@@ -1174,23 +1130,30 @@
bool mDesiredActiveConfigChanged GUARDED_BY(mActiveConfigLock) = false;
bool mCheckPendingFence = false;
- /* ------------------------------------------------------------------------ */
bool mLumaSampling = true;
sp<RegionSamplingThread> mRegionSamplingThread;
+ ui::DisplayPrimaries mInternalDisplayPrimaries;
sp<IInputFlinger> mInputFlinger;
-
InputWindowCommands mPendingInputWindowCommands GUARDED_BY(mStateLock);
// Should only be accessed by the main thread.
InputWindowCommands mInputWindowCommands;
- ui::DisplayPrimaries mInternalDisplayPrimaries;
- sp<SetInputWindowsListener> mSetInputWindowsListener;
+ struct SetInputWindowsListener : BnSetInputWindowsListener {
+ explicit SetInputWindowsListener(sp<SurfaceFlinger> flinger)
+ : mFlinger(std::move(flinger)) {}
+
+ void onSetInputWindowsFinished() override;
+
+ const sp<SurfaceFlinger> mFlinger;
+ };
+
+ const sp<SetInputWindowsListener> mSetInputWindowsListener = new SetInputWindowsListener(this);
+
bool mPendingSyncInputWindows GUARDED_BY(mStateLock);
Hwc2::impl::PowerAdvisor mPowerAdvisor;
std::unique_ptr<RefreshRateOverlay> mRefreshRateOverlay;
};
-}; // namespace android
-#endif // ANDROID_SURFACE_FLINGER_H
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index e130511..3522429 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -1,5 +1,18 @@
-
-#include <sysprop/SurfaceFlingerProperties.sysprop.h>
+/*
+ * 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 <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
@@ -225,6 +238,14 @@
return defaultValue;
}
+bool enable_protected_contents(bool defaultValue) {
+ auto temp = SurfaceFlingerProperties::enable_protected_contents();
+ if (temp.has_value()) {
+ return *temp;
+ }
+ return defaultValue;
+}
+
#define DISPLAY_PRIMARY_SIZE 3
constexpr float kSrgbRedX = 0.4123f;
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.h b/services/surfaceflinger/SurfaceFlingerProperties.h
index 6f90117..1864290 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.h
+++ b/services/surfaceflinger/SurfaceFlingerProperties.h
@@ -1,10 +1,25 @@
+/*
+ * 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 SURFACEFLINGERPROPERTIES_H_
#define SURFACEFLINGERPROPERTIES_H_
+#include <SurfaceFlingerProperties.sysprop.h>
#include <android/hardware/configstore/1.1/ISurfaceFlingerConfigs.h>
#include <android/hardware/graphics/common/1.2/types.h>
-#include <sysprop/SurfaceFlingerProperties.sysprop.h>
#include <ui/ConfigStoreTypes.h>
#include <cstdint>
@@ -59,6 +74,8 @@
bool use_smart_90_for_video(bool defaultValue);
+bool enable_protected_contents(bool defaultValue);
+
android::ui::DisplayPrimaries getDisplayNativePrimaries();
} // namespace sysprop
} // namespace android
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 4be2ee9..4773307 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -41,7 +41,7 @@
*/
class SurfaceTracing {
public:
- SurfaceTracing(SurfaceFlinger& flinger);
+ explicit SurfaceTracing(SurfaceFlinger& flinger);
void enable();
bool disable();
status_t writeToFile();
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index 6e0c1e2..6b2b583 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -29,6 +29,19 @@
namespace android {
+// Returns 0 if they are equal
+// <0 if the first id that doesn't match is lower in c2 or all ids match but c2 is shorter
+// >0 if the first id that doesn't match is greater in c2 or all ids match but c2 is longer
+//
+// See CallbackIdsHash for a explaniation of why this works
+static int compareCallbackIds(const std::vector<CallbackId>& c1,
+ const std::vector<CallbackId>& c2) {
+ if (c1.empty()) {
+ return !c2.empty();
+ }
+ return c1.front() - c2.front();
+}
+
TransactionCompletedThread::~TransactionCompletedThread() {
std::lock_guard lockThread(mThreadMutex);
@@ -44,8 +57,8 @@
{
std::lock_guard lock(mMutex);
- for (const auto& [listener, listenerStats] : mListenerStats) {
- listener->unlinkToDeath(mDeathRecipient);
+ for (const auto& [listener, transactionStats] : mCompletedTransactions) {
+ IInterface::asBinder(listener)->unlinkToDeath(mDeathRecipient);
}
}
}
@@ -62,85 +75,127 @@
mThread = std::thread(&TransactionCompletedThread::threadMain, this);
}
-void TransactionCompletedThread::registerPendingCallbackHandle(const sp<CallbackHandle>& handle) {
+status_t TransactionCompletedThread::addCallback(const sp<ITransactionCompletedListener>& listener,
+ const std::vector<CallbackId>& callbackIds) {
std::lock_guard lock(mMutex);
-
- sp<IBinder> listener = IInterface::asBinder(handle->listener);
- const auto& callbackIds = handle->callbackIds;
-
- mPendingTransactions[listener][callbackIds]++;
-}
-
-void TransactionCompletedThread::addPresentedCallbackHandles(
- const std::deque<sp<CallbackHandle>>& handles) {
- std::lock_guard lock(mMutex);
-
- for (const auto& handle : handles) {
- auto listener = mPendingTransactions.find(IInterface::asBinder(handle->listener));
- auto& pendingCallbacks = listener->second;
- auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
-
- if (pendingCallback != pendingCallbacks.end()) {
- auto& pendingCount = pendingCallback->second;
-
- // Decrease the pending count for this listener
- if (--pendingCount == 0) {
- pendingCallbacks.erase(pendingCallback);
- }
- } else {
- ALOGE("there are more latched callbacks than there were registered callbacks");
- }
-
- addCallbackHandle(handle);
- }
-}
-
-void TransactionCompletedThread::addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle) {
- std::lock_guard lock(mMutex);
- addCallbackHandle(handle);
-}
-
-void TransactionCompletedThread::addCallback(
- const sp<ITransactionCompletedListener>& transactionListener,
- const std::vector<CallbackId>& callbackIds) {
- std::lock_guard lock(mMutex);
- addCallbackLocked(transactionListener, callbackIds);
-}
-
-status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
- status_t err = addCallbackLocked(handle->listener, handle->callbackIds);
- if (err != NO_ERROR) {
- ALOGE("cannot add callback, err: %d", err);
- return err;
+ if (!mRunning) {
+ ALOGE("cannot add callback because the callback thread isn't running");
+ return BAD_VALUE;
}
- const sp<IBinder> listener = IInterface::asBinder(handle->listener);
- auto& listenerStats = mListenerStats[listener];
- auto& transactionStats = listenerStats.transactionStats[handle->callbackIds];
-
- transactionStats.latchTime = handle->latchTime;
- transactionStats.surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
- handle->previousReleaseFence);
- return NO_ERROR;
-}
-
-status_t TransactionCompletedThread::addCallbackLocked(
- const sp<ITransactionCompletedListener>& transactionListener,
- const std::vector<CallbackId>& callbackIds) {
- const sp<IBinder> listener = IInterface::asBinder(transactionListener);
- // If we don't already have a reference to this listener, linkToDeath so we get a notification
- // if it dies.
- if (mListenerStats.count(listener) == 0) {
- status_t err = listener->linkToDeath(mDeathRecipient);
+ if (mCompletedTransactions.count(listener) == 0) {
+ status_t err = IInterface::asBinder(listener)->linkToDeath(mDeathRecipient);
if (err != NO_ERROR) {
ALOGE("cannot add callback because linkToDeath failed, err: %d", err);
return err;
}
}
- auto& listenerStats = mListenerStats[listener];
- listenerStats.listener = transactionListener;
- listenerStats.transactionStats[callbackIds];
+ auto& transactionStatsDeque = mCompletedTransactions[listener];
+ transactionStatsDeque.emplace_back(callbackIds);
+ return NO_ERROR;
+}
+
+status_t TransactionCompletedThread::registerPendingCallbackHandle(
+ const sp<CallbackHandle>& handle) {
+ std::lock_guard lock(mMutex);
+ if (!mRunning) {
+ ALOGE("cannot register callback handle because the callback thread isn't running");
+ return BAD_VALUE;
+ }
+
+ // If we can't find the transaction stats something has gone wrong. The client should call
+ // addCallback before trying to register a pending callback handle.
+ TransactionStats* transactionStats;
+ status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
+ if (err != NO_ERROR) {
+ ALOGE("cannot find transaction stats");
+ return err;
+ }
+
+ mPendingTransactions[handle->listener][handle->callbackIds]++;
+ return NO_ERROR;
+}
+
+status_t TransactionCompletedThread::addPresentedCallbackHandles(
+ const std::deque<sp<CallbackHandle>>& handles) {
+ std::lock_guard lock(mMutex);
+ if (!mRunning) {
+ ALOGE("cannot add presented callback handle because the callback thread isn't running");
+ return BAD_VALUE;
+ }
+
+ for (const auto& handle : handles) {
+ auto listener = mPendingTransactions.find(handle->listener);
+ if (listener != mPendingTransactions.end()) {
+ auto& pendingCallbacks = listener->second;
+ auto pendingCallback = pendingCallbacks.find(handle->callbackIds);
+
+ if (pendingCallback != pendingCallbacks.end()) {
+ auto& pendingCount = pendingCallback->second;
+
+ // Decrease the pending count for this listener
+ if (--pendingCount == 0) {
+ pendingCallbacks.erase(pendingCallback);
+ }
+ } else {
+ ALOGW("there are more latched callbacks than there were registered callbacks");
+ }
+ } else {
+ ALOGW("cannot find listener in mPendingTransactions");
+ }
+
+ status_t err = addCallbackHandle(handle);
+ if (err != NO_ERROR) {
+ ALOGE("could not add callback handle");
+ return err;
+ }
+ }
+
+ return NO_ERROR;
+}
+
+status_t TransactionCompletedThread::addUnpresentedCallbackHandle(
+ const sp<CallbackHandle>& handle) {
+ std::lock_guard lock(mMutex);
+ if (!mRunning) {
+ ALOGE("cannot add unpresented callback handle because the callback thread isn't running");
+ return BAD_VALUE;
+ }
+
+ return addCallbackHandle(handle);
+}
+
+status_t TransactionCompletedThread::findTransactionStats(
+ const sp<ITransactionCompletedListener>& listener,
+ const std::vector<CallbackId>& callbackIds, TransactionStats** outTransactionStats) {
+ auto& transactionStatsDeque = mCompletedTransactions[listener];
+
+ // Search back to front because the most recent transactions are at the back of the deque
+ auto itr = transactionStatsDeque.rbegin();
+ for (; itr != transactionStatsDeque.rend(); itr++) {
+ if (compareCallbackIds(itr->callbackIds, callbackIds) == 0) {
+ *outTransactionStats = &(*itr);
+ return NO_ERROR;
+ }
+ }
+
+ ALOGE("could not find transaction stats");
+ return BAD_VALUE;
+}
+
+status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
+ // If we can't find the transaction stats something has gone wrong. The client should call
+ // addCallback before trying to add a presnted callback handle.
+ TransactionStats* transactionStats;
+ status_t err = findTransactionStats(handle->listener, handle->callbackIds, &transactionStats);
+ if (err != NO_ERROR) {
+ return err;
+ }
+
+ transactionStats->latchTime = handle->latchTime;
+ transactionStats->surfaceStats.emplace_back(handle->surfaceControl, handle->acquireTime,
+ handle->previousReleaseFence);
return NO_ERROR;
}
@@ -163,40 +218,46 @@
mConditionVariable.wait(mMutex);
// For each listener
- auto it = mListenerStats.begin();
- while (it != mListenerStats.end()) {
- auto& [listener, listenerStats] = *it;
+ auto completedTransactionsItr = mCompletedTransactions.begin();
+ while (completedTransactionsItr != mCompletedTransactions.end()) {
+ auto& [listener, transactionStatsDeque] = *completedTransactionsItr;
+ ListenerStats listenerStats;
+ listenerStats.listener = listener;
// For each transaction
- bool sendCallback = true;
- for (auto& [callbackIds, transactionStats] : listenerStats.transactionStats) {
- // If we are still waiting on the callback handles for this transaction, skip it
- if (mPendingTransactions[listener].count(callbackIds) != 0) {
- sendCallback = false;
+ auto transactionStatsItr = transactionStatsDeque.begin();
+ while (transactionStatsItr != transactionStatsDeque.end()) {
+ auto& transactionStats = *transactionStatsItr;
+
+ // If we are still waiting on the callback handles for this transaction, stop
+ // here because all transaction callbacks for the same listener must come in order
+ if (mPendingTransactions[listener].count(transactionStats.callbackIds) != 0) {
break;
}
// If the transaction has been latched
if (transactionStats.latchTime >= 0) {
if (!mPresentFence) {
- sendCallback = false;
break;
}
transactionStats.presentFence = mPresentFence;
}
+
+ // Remove the transaction from completed to the callback
+ listenerStats.transactionStats.push_back(std::move(transactionStats));
+ transactionStatsItr = transactionStatsDeque.erase(transactionStatsItr);
}
- // If the listener has no pending transactions and all latched transactions have been
- // presented
- if (sendCallback) {
+ // If the listener has completed transactions
+ if (!listenerStats.transactionStats.empty()) {
// If the listener is still alive
- if (listener->isBinderAlive()) {
+ if (IInterface::asBinder(listener)->isBinderAlive()) {
// Send callback
listenerStats.listener->onTransactionCompleted(listenerStats);
- listener->unlinkToDeath(mDeathRecipient);
+ IInterface::asBinder(listener)->unlinkToDeath(mDeathRecipient);
}
- it = mListenerStats.erase(it);
+ completedTransactionsItr = mCompletedTransactions.erase(completedTransactionsItr);
} else {
- it++;
+ completedTransactionsItr++;
}
}
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index 88808fd..21e2678 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -30,6 +30,18 @@
namespace android {
+struct CallbackIdsHash {
+ // CallbackId vectors have several properties that let us get away with this simple hash.
+ // 1) CallbackIds are never 0 so if something has gone wrong and our CallbackId vector is
+ // empty we can still hash 0.
+ // 2) CallbackId vectors for the same listener either are identical or contain none of the
+ // same members. It is sufficient to just check the first CallbackId in the vectors. If
+ // they match, they are the same. If they do not match, they are not the same.
+ std::size_t operator()(const std::vector<CallbackId>& callbackIds) const {
+ return std::hash<CallbackId>{}((callbackIds.empty()) ? 0 : callbackIds.front());
+ }
+};
+
class CallbackHandle : public RefBase {
public:
CallbackHandle(const sp<ITransactionCompletedListener>& transactionListener,
@@ -51,23 +63,24 @@
void run();
+ // Adds listener and callbackIds in case there are no SurfaceControls that are supposed
+ // to be included in the callback. This functions should be call before attempting to add any
+ // callback handles.
+ status_t addCallback(const sp<ITransactionCompletedListener>& transactionListener,
+ const std::vector<CallbackId>& callbackIds);
+
// Informs the TransactionCompletedThread that there is a Transaction with a CallbackHandle
// that needs to be latched and presented this frame. This function should be called once the
// layer has received the CallbackHandle so the TransactionCompletedThread knows not to send
// a callback for that Listener/Transaction pair until that CallbackHandle has been latched and
// presented.
- void registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
+ status_t registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
// Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
- void addPresentedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
+ status_t addPresentedCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
// Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
// presented this frame.
- void addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
-
- // Adds listener and callbackIds in case there are no SurfaceControls that are supposed
- // to be included in the callback.
- void addCallback(const sp<ITransactionCompletedListener>& transactionListener,
- const std::vector<CallbackId>& callbackIds);
+ status_t addUnpresentedCallbackHandle(const sp<CallbackHandle>& handle);
void addPresentFence(const sp<Fence>& presentFence);
@@ -76,9 +89,11 @@
private:
void threadMain();
+ status_t findTransactionStats(const sp<ITransactionCompletedListener>& listener,
+ const std::vector<CallbackId>& callbackIds,
+ TransactionStats** outTransactionStats) REQUIRES(mMutex);
+
status_t addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
- status_t addCallbackLocked(const sp<ITransactionCompletedListener>& transactionListener,
- const std::vector<CallbackId>& callbackIds) REQUIRES(mMutex);
class ThreadDeathRecipient : public IBinder::DeathRecipient {
public:
@@ -91,9 +106,10 @@
};
sp<ThreadDeathRecipient> mDeathRecipient;
- struct IBinderHash {
- std::size_t operator()(const sp<IBinder>& strongPointer) const {
- return std::hash<IBinder*>{}(strongPointer.get());
+ struct ITransactionCompletedListenerHash {
+ std::size_t operator()(const sp<ITransactionCompletedListener>& listener) const {
+ return std::hash<IBinder*>{}((listener) ? IInterface::asBinder(listener).get()
+ : nullptr);
}
};
@@ -106,12 +122,13 @@
std::condition_variable_any mConditionVariable;
std::unordered_map<
- sp<IBinder /*listener*/>,
+ sp<ITransactionCompletedListener>,
std::unordered_map<std::vector<CallbackId>, uint32_t /*count*/, CallbackIdsHash>,
- IBinderHash>
+ ITransactionCompletedListenerHash>
mPendingTransactions GUARDED_BY(mMutex);
- std::unordered_map<sp<IBinder /*listener*/>, ListenerStats, IBinderHash> mListenerStats
- GUARDED_BY(mMutex);
+ std::unordered_map<sp<ITransactionCompletedListener>, std::deque<TransactionStats>,
+ ITransactionCompletedListenerHash>
+ mCompletedTransactions GUARDED_BY(mMutex);
bool mRunning GUARDED_BY(mMutex) = false;
bool mKeepRunning GUARDED_BY(mMutex) = true;
diff --git a/services/surfaceflinger/sysprop/Android.bp b/services/surfaceflinger/sysprop/Android.bp
new file mode 100644
index 0000000..7721d7d2
--- /dev/null
+++ b/services/surfaceflinger/sysprop/Android.bp
@@ -0,0 +1,6 @@
+sysprop_library {
+ name: "SurfaceFlingerProperties",
+ srcs: ["*.sysprop"],
+ api_packages: ["android.sysprop"],
+ property_owner: "Platform",
+}
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index fe6dc93..830c03e 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -307,3 +307,11 @@
access: Readonly
prop_name: "ro.surface_flinger.use_smart_90_for_video"
}
+
+prop {
+ api_name: "enable_protected_contents"
+ type: Boolean
+ scope: Internal
+ access: Readonly
+ prop_name: "ro.surface_flinger.protected_contents"
+}
diff --git a/services/surfaceflinger/sysprop/api/current.txt b/services/surfaceflinger/sysprop/api/current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/removed.txt b/services/surfaceflinger/sysprop/api/removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/system-current.txt b/services/surfaceflinger/sysprop/api/system-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/system-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/system-removed.txt b/services/surfaceflinger/sysprop/api/system-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/system-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/test-current.txt b/services/surfaceflinger/sysprop/api/test-current.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/test-current.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/sysprop/api/test-removed.txt b/services/surfaceflinger/sysprop/api/test-removed.txt
new file mode 100644
index 0000000..d802177
--- /dev/null
+++ b/services/surfaceflinger/sysprop/api/test-removed.txt
@@ -0,0 +1 @@
+// Signature format: 2.0
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index ea2818d..ef3dfef 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -175,7 +175,6 @@
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
mock::DispSync* mPrimaryDispSync = new mock::DispSync();
- renderengine::mock::Framebuffer* mReFrameBuffer = new renderengine::mock::Framebuffer();
sp<Fence> mClientTargetAcquireFence = Fence::NO_FENCE;
@@ -312,8 +311,8 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly(
[](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
- ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*) -> status_t {
+ const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
+ const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -351,8 +350,8 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillRepeatedly(
[](const renderengine::DisplaySettings& displaySettings,
- const std::vector<renderengine::LayerSettings>& /*layerSettings*/,
- ANativeWindowBuffer*, base::unique_fd&&, base::unique_fd*) -> status_t {
+ const std::vector<renderengine::LayerSettings>&, ANativeWindowBuffer*,
+ const bool, base::unique_fd&&, base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
displaySettings.physicalDisplay);
@@ -581,7 +580,7 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& layerSettings,
- ANativeWindowBuffer*, base::unique_fd&&,
+ ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -624,7 +623,7 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& layerSettings,
- ANativeWindowBuffer*, base::unique_fd&&,
+ ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
@@ -694,7 +693,7 @@
EXPECT_CALL(*test->mRenderEngine, drawLayers)
.WillOnce([](const renderengine::DisplaySettings& displaySettings,
const std::vector<renderengine::LayerSettings>& layerSettings,
- ANativeWindowBuffer*, base::unique_fd&&,
+ ANativeWindowBuffer*, const bool, base::unique_fd&&,
base::unique_fd*) -> status_t {
EXPECT_EQ(DEFAULT_DISPLAY_MAX_LUMINANCE, displaySettings.maxLuminance);
EXPECT_EQ(Rect(DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 406ec81..249c78f 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -38,6 +38,7 @@
constexpr PhysicalDisplayId INTERNAL_DISPLAY_ID = 111;
constexpr PhysicalDisplayId EXTERNAL_DISPLAY_ID = 222;
+constexpr PhysicalDisplayId DISPLAY_ID_64BIT = 0xabcd12349876fedcULL;
class MockVSyncSource : public VSyncSource {
public:
@@ -470,5 +471,10 @@
expectConfigChangedEventReceivedByConnection(EXTERNAL_DISPLAY_ID, 5);
}
+TEST_F(EventThreadTest, postConfigChangedPrimary64bit) {
+ mThread->onConfigChanged(DISPLAY_ID_64BIT, 7);
+ expectConfigChangedEventReceivedByConnection(DISPLAY_ID_64BIT, 7);
+}
+
} // namespace
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 46fd964..81235ba 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -31,6 +31,7 @@
#include "FakePhaseOffsets.h"
#include "Layer.h"
#include "NativeWindowSurface.h"
+#include "Scheduler/MessageQueue.h"
#include "StartPropertySetThread.h"
#include "SurfaceFlinger.h"
#include "SurfaceFlingerFactory.h"
@@ -276,8 +277,9 @@
auto onMessageReceived(int32_t what) { return mFlinger->onMessageReceived(what); }
auto captureScreenImplLocked(const RenderArea& renderArea,
- TraverseLayersFunction traverseLayers, ANativeWindowBuffer* buffer,
- bool useIdentityTransform, bool forSystem, int* outSyncFd) {
+ SurfaceFlinger::TraverseLayersFunction traverseLayers,
+ ANativeWindowBuffer* buffer, bool useIdentityTransform,
+ bool forSystem, int* outSyncFd) {
return mFlinger->captureScreenImplLocked(renderArea, traverseLayers, buffer,
useIdentityTransform, forSystem, outSyncFd);
}
diff --git a/services/vr/bufferhubd/Android.bp b/services/vr/bufferhubd/Android.bp
index 4e24a64..afb3004 100644
--- a/services/vr/bufferhubd/Android.bp
+++ b/services/vr/bufferhubd/Android.bp
@@ -44,9 +44,6 @@
static_libs: [
"libbufferhub",
],
-
- // TODO(b/117568153): Temporarily opt out using libcrt.
- no_libcrt: true,
}
cc_binary {