Merge "InputDevice.hasKeys also checks for key usage" into udc-dev
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 84900a7..f2b4a6e 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -190,7 +190,8 @@
data.writeInt32(apiType);
data.writeInt32(appUid);
data.writeInt32(appPid);
- status_t err = remote()->transact(LOG_FGS_API_BEGIN_TRANSACTION, data, &reply);
+ status_t err = remote()->transact(LOG_FGS_API_BEGIN_TRANSACTION, data, &reply,
+ IBinder::FLAG_ONEWAY);
if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
ALOGD("FGS Logger Transaction failed");
ALOGD("%d", err);
@@ -205,7 +206,8 @@
data.writeInt32(apiType);
data.writeInt32(appUid);
data.writeInt32(appPid);
- status_t err = remote()->transact(LOG_FGS_API_END_TRANSACTION, data, &reply);
+ status_t err =
+ remote()->transact(LOG_FGS_API_END_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
ALOGD("FGS Logger Transaction failed");
ALOGD("%d", err);
@@ -222,7 +224,8 @@
data.writeInt32(state);
data.writeInt32(appUid);
data.writeInt32(appPid);
- status_t err = remote()->transact(LOG_FGS_API_BEGIN_TRANSACTION, data, &reply);
+ status_t err = remote()->transact(LOG_FGS_API_BEGIN_TRANSACTION, data, &reply,
+ IBinder::FLAG_ONEWAY);
if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) {
ALOGD("FGS Logger Transaction failed");
ALOGD("%d", err);
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 80fed98..bf34987 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -217,6 +217,7 @@
"DebugEGLImageTracker.cpp",
"DisplayEventDispatcher.cpp",
"DisplayEventReceiver.cpp",
+ "FenceMonitor.cpp",
"GLConsumer.cpp",
"IConsumerListener.cpp",
"IGraphicBufferConsumer.cpp",
diff --git a/libs/gui/FenceMonitor.cpp b/libs/gui/FenceMonitor.cpp
new file mode 100644
index 0000000..230c81a
--- /dev/null
+++ b/libs/gui/FenceMonitor.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <gui/FenceMonitor.h>
+#include <gui/TraceUtils.h>
+#include <log/log.h>
+
+#include <thread>
+
+namespace android::gui {
+
+FenceMonitor::FenceMonitor(const char* name) : mName(name), mFencesQueued(0), mFencesSignaled(0) {
+ std::thread thread(&FenceMonitor::loop, this);
+ pthread_setname_np(thread.native_handle(), mName);
+ thread.detach();
+}
+
+void FenceMonitor::queueFence(const sp<Fence>& fence) {
+ char message[64];
+
+ std::lock_guard<std::mutex> lock(mMutex);
+ if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
+ snprintf(message, sizeof(message), "%s fence %u has signaled", mName, mFencesQueued);
+ ATRACE_NAME(message);
+ // Need an increment on both to make the trace number correct.
+ mFencesQueued++;
+ mFencesSignaled++;
+ return;
+ }
+ snprintf(message, sizeof(message), "Trace %s fence %u", mName, mFencesQueued);
+ ATRACE_NAME(message);
+
+ mQueue.push_back(fence);
+ mCondition.notify_one();
+ mFencesQueued++;
+ ATRACE_INT(mName, int32_t(mQueue.size()));
+}
+
+void FenceMonitor::loop() {
+ while (true) {
+ threadLoop();
+ }
+}
+
+void FenceMonitor::threadLoop() {
+ sp<Fence> fence;
+ uint32_t fenceNum;
+ {
+ std::unique_lock<std::mutex> lock(mMutex);
+ while (mQueue.empty()) {
+ mCondition.wait(lock);
+ }
+ fence = mQueue[0];
+ fenceNum = mFencesSignaled;
+ }
+ {
+ char message[64];
+ snprintf(message, sizeof(message), "waiting for %s %u", mName, fenceNum);
+ ATRACE_NAME(message);
+
+ status_t result = fence->waitForever(message);
+ if (result != OK) {
+ ALOGE("Error waiting for fence: %d", result);
+ }
+ }
+ {
+ std::lock_guard<std::mutex> lock(mMutex);
+ mQueue.pop_front();
+ mFencesSignaled++;
+ ATRACE_INT(mName, int32_t(mQueue.size()));
+ }
+}
+
+} // namespace android::gui
\ No newline at end of file
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index d72f65e..b526a6c 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -59,15 +59,13 @@
virtual ~BpSurfaceComposer();
- status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
- Vector<ComposerState>& state, const Vector<DisplayState>& displays,
- uint32_t flags, const sp<IBinder>& applyToken,
- InputWindowCommands commands, int64_t desiredPresentTime,
- bool isAutoTimestamp,
- const std::vector<client_cache_t>& uncacheBuffers,
- bool hasListenerCallbacks,
- const std::vector<ListenerCallbacks>& listenerCallbacks,
- uint64_t transactionId) override {
+ status_t setTransactionState(
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state,
+ const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ InputWindowCommands commands, int64_t desiredPresentTime, bool isAutoTimestamp,
+ const std::vector<client_cache_t>& uncacheBuffers, bool hasListenerCallbacks,
+ const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId,
+ const std::vector<uint64_t>& mergedTransactionIds) override {
Parcel data, reply;
data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -103,6 +101,11 @@
SAFE_PARCEL(data.writeUint64, transactionId);
+ SAFE_PARCEL(data.writeUint32, static_cast<uint32_t>(mergedTransactionIds.size()));
+ for (auto mergedTransactionId : mergedTransactionIds) {
+ SAFE_PARCEL(data.writeUint64, mergedTransactionId);
+ }
+
if (flags & ISurfaceComposer::eOneWay) {
return remote()->transact(BnSurfaceComposer::SET_TRANSACTION_STATE,
data, &reply, IBinder::FLAG_ONEWAY);
@@ -187,10 +190,16 @@
uint64_t transactionId = -1;
SAFE_PARCEL(data.readUint64, &transactionId);
+ SAFE_PARCEL_READ_SIZE(data.readUint32, &count, data.dataSize());
+ std::vector<uint64_t> mergedTransactions(count);
+ for (size_t i = 0; i < count; i++) {
+ SAFE_PARCEL(data.readUint64, &mergedTransactions[i]);
+ }
+
return setTransactionState(frameTimelineInfo, state, displays, stateFlags, applyToken,
std::move(inputWindowCommands), desiredPresentTime,
isAutoTimestamp, uncacheBuffers, hasListenerCallbacks,
- listenerCallbacks, transactionId);
+ listenerCallbacks, transactionId, mergedTransactions);
}
default: {
return BBinder::onTransact(code, data, reply, flags);
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 44d3594..ed69100 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -30,6 +30,7 @@
#include <android/gui/DisplayStatInfo.h>
#include <android/native_window.h>
+#include <gui/FenceMonitor.h>
#include <gui/TraceUtils.h>
#include <utils/Log.h>
#include <utils/NativeHandle.h>
@@ -545,82 +546,6 @@
return NO_ERROR;
}
-class FenceMonitor {
-public:
- explicit FenceMonitor(const char* name) : mName(name), mFencesQueued(0), mFencesSignaled(0) {
- std::thread thread(&FenceMonitor::loop, this);
- pthread_setname_np(thread.native_handle(), mName);
- thread.detach();
- }
-
- void queueFence(const sp<Fence>& fence) {
- char message[64];
-
- std::lock_guard<std::mutex> lock(mMutex);
- if (fence->getSignalTime() != Fence::SIGNAL_TIME_PENDING) {
- snprintf(message, sizeof(message), "%s fence %u has signaled", mName, mFencesQueued);
- ATRACE_NAME(message);
- // Need an increment on both to make the trace number correct.
- mFencesQueued++;
- mFencesSignaled++;
- return;
- }
- snprintf(message, sizeof(message), "Trace %s fence %u", mName, mFencesQueued);
- ATRACE_NAME(message);
-
- mQueue.push_back(fence);
- mCondition.notify_one();
- mFencesQueued++;
- ATRACE_INT(mName, int32_t(mQueue.size()));
- }
-
-private:
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wmissing-noreturn"
- void loop() {
- while (true) {
- threadLoop();
- }
- }
-#pragma clang diagnostic pop
-
- void threadLoop() {
- sp<Fence> fence;
- uint32_t fenceNum;
- {
- std::unique_lock<std::mutex> lock(mMutex);
- while (mQueue.empty()) {
- mCondition.wait(lock);
- }
- fence = mQueue[0];
- fenceNum = mFencesSignaled;
- }
- {
- char message[64];
- snprintf(message, sizeof(message), "waiting for %s %u", mName, fenceNum);
- ATRACE_NAME(message);
-
- status_t result = fence->waitForever(message);
- if (result != OK) {
- ALOGE("Error waiting for fence: %d", result);
- }
- }
- {
- std::lock_guard<std::mutex> lock(mMutex);
- mQueue.pop_front();
- mFencesSignaled++;
- ATRACE_INT(mName, int32_t(mQueue.size()));
- }
- }
-
- const char* mName;
- uint32_t mFencesQueued;
- uint32_t mFencesSignaled;
- std::deque<sp<Fence>> mQueue;
- std::condition_variable mCondition;
- std::mutex mMutex;
-};
-
void Surface::getDequeueBufferInputLocked(
IGraphicBufferProducer::DequeueBufferInput* dequeueInput) {
LOG_ALWAYS_FATAL_IF(dequeueInput == nullptr, "input is null");
@@ -694,7 +619,7 @@
ALOGE_IF(fence == nullptr, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) {
- static FenceMonitor hwcReleaseThread("HWC release");
+ static gui::FenceMonitor hwcReleaseThread("HWC release");
hwcReleaseThread.queueFence(fence);
}
@@ -893,7 +818,7 @@
sp<GraphicBuffer>& gbuf(mSlots[slot].buffer);
if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) {
- static FenceMonitor hwcReleaseThread("HWC release");
+ static gui::FenceMonitor hwcReleaseThread("HWC release");
hwcReleaseThread.queueFence(output.fence);
}
@@ -1163,7 +1088,7 @@
mQueueBufferCondition.broadcast();
if (CC_UNLIKELY(atrace_is_tag_enabled(ATRACE_TAG_GRAPHICS))) {
- static FenceMonitor gpuCompletionThread("GPU completion");
+ static gui::FenceMonitor gpuCompletionThread("GPU completion");
gpuCompletionThread.queueFence(fence);
}
}
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index c6c7367..0fda358 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -827,6 +827,15 @@
SAFE_PARCEL(parcel->readUint64, &uncacheBuffers[i].id);
}
+ count = static_cast<size_t>(parcel->readUint32());
+ if (count > parcel->dataSize()) {
+ return BAD_VALUE;
+ }
+ std::vector<uint64_t> mergedTransactionIds(count);
+ for (size_t i = 0; i < count; i++) {
+ SAFE_PARCEL(parcel->readUint64, &mergedTransactionIds[i]);
+ }
+
// Parsing was successful. Update the object.
mId = transactionId;
mTransactionNestCount = transactionNestCount;
@@ -842,6 +851,7 @@
mInputWindowCommands = inputWindowCommands;
mApplyToken = applyToken;
mUncacheBuffers = std::move(uncacheBuffers);
+ mMergedTransactionIds = std::move(mergedTransactionIds);
return NO_ERROR;
}
@@ -900,6 +910,11 @@
SAFE_PARCEL(parcel->writeUint64, uncacheBuffer.id);
}
+ SAFE_PARCEL(parcel->writeUint32, static_cast<uint32_t>(mMergedTransactionIds.size()));
+ for (auto mergedTransactionId : mMergedTransactionIds) {
+ SAFE_PARCEL(parcel->writeUint64, mergedTransactionId);
+ }
+
return NO_ERROR;
}
@@ -924,6 +939,22 @@
}
SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::merge(Transaction&& other) {
+ while (mMergedTransactionIds.size() + other.mMergedTransactionIds.size() >
+ MAX_MERGE_HISTORY_LENGTH - 1 &&
+ mMergedTransactionIds.size() > 0) {
+ mMergedTransactionIds.pop_back();
+ }
+ if (other.mMergedTransactionIds.size() == MAX_MERGE_HISTORY_LENGTH) {
+ mMergedTransactionIds.insert(mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.end() - 1);
+ } else if (other.mMergedTransactionIds.size() > 0u) {
+ mMergedTransactionIds.insert(mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.begin(),
+ other.mMergedTransactionIds.end());
+ }
+ mMergedTransactionIds.insert(mMergedTransactionIds.begin(), other.mId);
+
for (auto const& [handle, composerState] : other.mComposerStates) {
if (mComposerStates.count(handle) == 0) {
mComposerStates[handle] = composerState;
@@ -998,12 +1029,17 @@
mIsAutoTimestamp = true;
clearFrameTimelineInfo(mFrameTimelineInfo);
mApplyToken = nullptr;
+ mMergedTransactionIds.clear();
}
uint64_t SurfaceComposerClient::Transaction::getId() {
return mId;
}
+std::vector<uint64_t> SurfaceComposerClient::Transaction::getMergedTransactionIds() {
+ return mMergedTransactionIds;
+}
+
void SurfaceComposerClient::doUncacheBufferTransaction(uint64_t cacheId) {
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
@@ -1014,7 +1050,7 @@
status_t status = sf->setTransactionState(FrameTimelineInfo{}, composerStates, {},
ISurfaceComposer::eOneWay,
Transaction::getDefaultApplyToken(), {}, systemTime(),
- true, {uncacheBuffer}, false, {}, generateId());
+ true, {uncacheBuffer}, false, {}, generateId(), {});
if (status != NO_ERROR) {
ALOGE_AND_TRACE("SurfaceComposerClient::doUncacheBufferTransaction - %s",
strerror(-status));
@@ -1189,7 +1225,8 @@
sp<ISurfaceComposer> sf(ComposerService::getComposerService());
sf->setTransactionState(mFrameTimelineInfo, composerStates, displayStates, flags, applyToken,
mInputWindowCommands, mDesiredPresentTime, mIsAutoTimestamp,
- mUncacheBuffers, hasListenerCallbacks, listenerCallbacks, mId);
+ mUncacheBuffers, hasListenerCallbacks, listenerCallbacks, mId,
+ mMergedTransactionIds);
mId = generateId();
// Clear the current states and flags
diff --git a/libs/gui/include/gui/FenceMonitor.h b/libs/gui/include/gui/FenceMonitor.h
new file mode 100644
index 0000000..62cedde
--- /dev/null
+++ b/libs/gui/include/gui/FenceMonitor.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <cstdint>
+#include <deque>
+#include <mutex>
+
+#include <ui/Fence.h>
+
+namespace android::gui {
+
+class FenceMonitor {
+public:
+ explicit FenceMonitor(const char* name);
+ void queueFence(const sp<Fence>& fence);
+
+private:
+ void loop();
+ void threadLoop();
+
+ const char* mName;
+ uint32_t mFencesQueued;
+ uint32_t mFencesSignaled;
+ std::deque<sp<Fence>> mQueue;
+ std::condition_variable mCondition;
+ std::mutex mMutex;
+};
+
+} // namespace android::gui
\ No newline at end of file
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index bd21851..7c150d5 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -116,7 +116,7 @@
InputWindowCommands inputWindowCommands, int64_t desiredPresentTime,
bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffer,
bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
- uint64_t transactionId) = 0;
+ uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) = 0;
};
// ----------------------------------------------------------------------------
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 8d2cdaf..fb57f63 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -419,6 +419,11 @@
mListenerCallbacks;
std::vector<client_cache_t> mUncacheBuffers;
+ // We keep track of the last MAX_MERGE_HISTORY_LENGTH merged transaction ids.
+ // Ordered most recently merged to least recently merged.
+ static const size_t MAX_MERGE_HISTORY_LENGTH = 10u;
+ std::vector<uint64_t> mMergedTransactionIds;
+
uint64_t mId;
uint32_t mTransactionNestCount = 0;
@@ -482,6 +487,8 @@
// The id is updated every time the transaction is applied.
uint64_t getId();
+ std::vector<uint64_t> getMergedTransactionIds();
+
status_t apply(bool synchronous = false, bool oneWay = false);
// Merge another transaction in to this one, clearing other
// as if it had been applied.
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 5bc6904..096a43c 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -695,16 +695,14 @@
mSupportsPresent = supportsPresent;
}
- status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
- Vector<ComposerState>& /*state*/,
- const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
- const sp<IBinder>& /*applyToken*/,
- InputWindowCommands /*inputWindowCommands*/,
- int64_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/,
- const std::vector<client_cache_t>& /*cachedBuffer*/,
- bool /*hasListenerCallbacks*/,
- const std::vector<ListenerCallbacks>& /*listenerCallbacks*/,
- uint64_t /*transactionId*/) override {
+ status_t setTransactionState(
+ const FrameTimelineInfo& /*frameTimelineInfo*/, Vector<ComposerState>& /*state*/,
+ const Vector<DisplayState>& /*displays*/, uint32_t /*flags*/,
+ const sp<IBinder>& /*applyToken*/, InputWindowCommands /*inputWindowCommands*/,
+ int64_t /*desiredPresentTime*/, bool /*isAutoTimestamp*/,
+ const std::vector<client_cache_t>& /*cachedBuffer*/, bool /*hasListenerCallbacks*/,
+ const std::vector<ListenerCallbacks>& /*listenerCallbacks*/, uint64_t /*transactionId*/,
+ const std::vector<uint64_t>& /*mergedTransactionIds*/) override {
return NO_ERROR;
}
diff --git a/libs/permission/AppOpsManager.cpp b/libs/permission/AppOpsManager.cpp
index baa9d75..6959274 100644
--- a/libs/permission/AppOpsManager.cpp
+++ b/libs/permission/AppOpsManager.cpp
@@ -146,6 +146,14 @@
}
}
+void AppOpsManager::startWatchingMode(int32_t op, const String16& packageName, int32_t flags,
+ const sp<IAppOpsCallback>& callback) {
+ sp<IAppOpsService> service = getService();
+ if (service != nullptr) {
+ service->startWatchingModeWithFlags(op, packageName, flags, callback);
+ }
+}
+
void AppOpsManager::stopWatchingMode(const sp<IAppOpsCallback>& callback) {
sp<IAppOpsService> service = getService();
if (service != nullptr) {
diff --git a/libs/permission/IAppOpsService.cpp b/libs/permission/IAppOpsService.cpp
index d59f445..7f235a4 100644
--- a/libs/permission/IAppOpsService.cpp
+++ b/libs/permission/IAppOpsService.cpp
@@ -166,6 +166,17 @@
}
return reply.readBool();
}
+
+ virtual void startWatchingModeWithFlags(int32_t op, const String16& packageName,
+ int32_t flags, const sp<IAppOpsCallback>& callback) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAppOpsService::getInterfaceDescriptor());
+ data.writeInt32(op);
+ data.writeString16(packageName);
+ data.writeInt32(flags);
+ data.writeStrongBinder(IInterface::asBinder(callback));
+ remote()->transact(START_WATCHING_MODE_WITH_FLAGS_TRANSACTION, data, &reply);
+ }
};
IMPLEMENT_META_INTERFACE(AppOpsService, "com.android.internal.app.IAppOpsService")
diff --git a/libs/permission/include/binder/AppOpsManager.h b/libs/permission/include/binder/AppOpsManager.h
index abcd527..243532b 100644
--- a/libs/permission/include/binder/AppOpsManager.h
+++ b/libs/permission/include/binder/AppOpsManager.h
@@ -151,6 +151,10 @@
_NUM_OP = 117
};
+ enum {
+ WATCH_FOREGROUND_CHANGES = 1 << 0
+ };
+
AppOpsManager();
int32_t checkOp(int32_t op, int32_t uid, const String16& callingPackage);
@@ -174,6 +178,8 @@
const std::optional<String16>& attributionTag);
void startWatchingMode(int32_t op, const String16& packageName,
const sp<IAppOpsCallback>& callback);
+ void startWatchingMode(int32_t op, const String16& packageName, int32_t flags,
+ const sp<IAppOpsCallback>& callback);
void stopWatchingMode(const sp<IAppOpsCallback>& callback);
int32_t permissionToOpCode(const String16& permission);
void setCameraAudioRestriction(int32_t mode);
diff --git a/libs/permission/include/binder/IAppOpsService.h b/libs/permission/include/binder/IAppOpsService.h
index 22f056b..918fcdb 100644
--- a/libs/permission/include/binder/IAppOpsService.h
+++ b/libs/permission/include/binder/IAppOpsService.h
@@ -52,6 +52,8 @@
const String16& packageName) = 0;
virtual void setCameraAudioRestriction(int32_t mode) = 0;
virtual bool shouldCollectNotes(int32_t opCode) = 0;
+ virtual void startWatchingModeWithFlags(int32_t op, const String16& packageName,
+ int32_t flags, const sp<IAppOpsCallback>& callback) = 0;
enum {
CHECK_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
@@ -64,6 +66,7 @@
CHECK_AUDIO_OPERATION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+7,
SHOULD_COLLECT_NOTES_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+8,
SET_CAMERA_AUDIO_RESTRICTION_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+9,
+ START_WATCHING_MODE_WITH_FLAGS_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION+10,
};
enum {
diff --git a/libs/renderengine/skia/SkiaRenderEngine.cpp b/libs/renderengine/skia/SkiaRenderEngine.cpp
index cfea85f..5854135 100644
--- a/libs/renderengine/skia/SkiaRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaRenderEngine.cpp
@@ -39,10 +39,10 @@
#include <SkPath.h>
#include <SkPoint.h>
#include <SkPoint3.h>
+#include <SkRRect.h>
#include <SkRect.h>
#include <SkRefCnt.h>
#include <SkRegion.h>
-#include <SkRRect.h>
#include <SkRuntimeEffect.h>
#include <SkSamplingOptions.h>
#include <SkScalar.h>
@@ -51,9 +51,11 @@
#include <SkString.h>
#include <SkSurface.h>
#include <SkTileMode.h>
-#include <src/core/SkTraceEventCommon.h>
#include <android-base/stringprintf.h>
+#include <gui/FenceMonitor.h>
#include <gui/TraceUtils.h>
+#include <pthread.h>
+#include <src/core/SkTraceEventCommon.h>
#include <sync/sync.h>
#include <ui/BlurRegion.h>
#include <ui/DataspaceUtils.h>
@@ -63,6 +65,7 @@
#include <cmath>
#include <cstdint>
+#include <deque>
#include <memory>
#include <numeric>
@@ -229,7 +232,6 @@
static inline SkPoint3 getSkPoint3(const android::vec3& vector) {
return SkPoint3::Make(vector.x, vector.y, vector.z);
}
-
} // namespace
namespace android {
@@ -1134,8 +1136,13 @@
activeSurface->flush();
}
- base::unique_fd drawFence = flushAndSubmit(grContext);
- resultPromise->set_value(sp<Fence>::make(std::move(drawFence)));
+ auto drawFence = sp<Fence>::make(flushAndSubmit(grContext));
+
+ if (ATRACE_ENABLED()) {
+ static gui::FenceMonitor sMonitor("RE Completion");
+ sMonitor.queueFence(drawFence);
+ }
+ resultPromise->set_value(std::move(drawFence));
}
size_t SkiaRenderEngine::getMaxTextureSize() const {
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index f3ada8e..a3c129e 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -681,6 +681,25 @@
return left;
}
+// Filter windows in a TouchState and targets in a vector to remove untrusted windows/targets from
+// both.
+void filterUntrustedTargets(TouchState& touchState, std::vector<InputTarget>& targets) {
+ std::erase_if(touchState.windows, [&](const TouchedWindow& window) {
+ if (!window.windowHandle->getInfo()->inputConfig.test(
+ WindowInfo::InputConfig::TRUSTED_OVERLAY)) {
+ // In addition to TouchState, erase this window from the input targets! We don't have a
+ // good way to do this today except by adding a nested loop.
+ // TODO(b/282025641): simplify this code once InputTargets are being identified
+ // separately from TouchedWindows.
+ std::erase_if(targets, [&](const InputTarget& target) {
+ return target.inputChannel->getConnectionToken() == window.windowHandle->getToken();
+ });
+ return true;
+ }
+ return false;
+ });
+}
+
} // namespace
// --- InputDispatcher ---
@@ -2588,6 +2607,14 @@
}
}
+ // If this is a touchpad navigation gesture, it needs to only be sent to trusted targets, as we
+ // only want the system UI to handle these gestures.
+ const bool isTouchpadNavGesture = isFromSource(entry.source, AINPUT_SOURCE_MOUSE) &&
+ entry.classification == MotionClassification::MULTI_FINGER_SWIPE;
+ if (isTouchpadNavGesture) {
+ filterUntrustedTargets(/* byref */ tempTouchState, /* byref */ targets);
+ }
+
// Output targets from the touch state.
for (const TouchedWindow& touchedWindow : tempTouchState.windows) {
if (touchedWindow.pointerIds.none() && !touchedWindow.hasHoveringPointers(entry.deviceId)) {
@@ -2595,6 +2622,7 @@
// Do not send this event to those windows.
continue;
}
+
addWindowTargetLocked(touchedWindow.windowHandle, touchedWindow.targetFlags,
touchedWindow.pointerIds, touchedWindow.firstDownTimeInTarget,
targets);
diff --git a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
index dab4661..061c6a3 100644
--- a/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
+++ b/services/inputflinger/reader/mapper/CapturedTouchpadEventConverter.cpp
@@ -199,6 +199,29 @@
}
}
+ // Send BUTTON_RELEASE events. (This has to happen before any UP events to avoid sending
+ // BUTTON_RELEASE events without any pointers.)
+ uint32_t newButtonState;
+ if (coords.size() - upSlots.size() + downSlots.size() == 0) {
+ // If there won't be any pointers down after this evdev sync, we won't be able to send
+ // button updates on their own, as motion events without pointers are invalid. To avoid
+ // erroneously reporting buttons being held for long periods, send BUTTON_RELEASE events for
+ // all pressed buttons when the last pointer is lifted.
+ //
+ // This also prevents us from sending BUTTON_PRESS events too early in the case of touchpads
+ // which report a button press one evdev sync before reporting a touch going down.
+ newButtonState = 0;
+ } else {
+ newButtonState = mCursorButtonAccumulator.getButtonState();
+ }
+ for (uint32_t button = 1; button <= AMOTION_EVENT_BUTTON_FORWARD; button <<= 1) {
+ if (!(newButtonState & button) && mButtonState & button) {
+ mButtonState &= ~button;
+ out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
+ coords, properties, /*actionButton=*/button));
+ }
+ }
+
// For any touches that were lifted, send UP or POINTER_UP events.
for (size_t slotNumber : upSlots) {
const size_t indexToRemove = coordsIndexForSlotNumber.at(slotNumber);
@@ -240,16 +263,11 @@
out.push_back(makeMotionArgs(when, readTime, action, coords, properties));
}
- const uint32_t newButtonState = mCursorButtonAccumulator.getButtonState();
for (uint32_t button = 1; button <= AMOTION_EVENT_BUTTON_FORWARD; button <<= 1) {
if (newButtonState & button && !(mButtonState & button)) {
mButtonState |= button;
out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_PRESS, coords,
properties, /*actionButton=*/button));
- } else if (!(newButtonState & button) && mButtonState & button) {
- mButtonState &= ~button;
- out.push_back(makeMotionArgs(when, readTime, AMOTION_EVENT_ACTION_BUTTON_RELEASE,
- coords, properties, /*actionButton=*/button));
}
}
return out;
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
index fd2be5f..7eca6fa 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.cpp
@@ -132,7 +132,7 @@
case kGestureTypeScroll:
return handleScroll(when, readTime, gesture);
case kGestureTypeFling:
- return {handleFling(when, readTime, gesture)};
+ return handleFling(when, readTime, gesture);
case kGestureTypeSwipe:
return handleMultiFingerSwipe(when, readTime, 3, gesture.details.swipe.dx,
gesture.details.swipe.dy);
@@ -149,7 +149,8 @@
}
}
-NotifyArgs GestureConverter::handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture) {
+NotifyMotionArgs GestureConverter::handleMove(nsecs_t when, nsecs_t readTime,
+ const Gesture& gesture) {
float deltaX = gesture.details.move.dx;
float deltaY = gesture.details.move.dy;
rotateDelta(mOrientation, &deltaX, &deltaY);
@@ -312,19 +313,39 @@
return out;
}
-NotifyArgs GestureConverter::handleFling(nsecs_t when, nsecs_t readTime, const Gesture& gesture) {
- // We don't actually want to use the gestures library's fling velocity values (to ensure
- // consistency between touchscreen and touchpad flings), so we're just using the "start fling"
- // gestures as a marker for the end of a two-finger scroll gesture.
- if (gesture.details.fling.fling_state != GESTURES_FLING_START ||
- mCurrentClassification != MotionClassification::TWO_FINGER_SWIPE) {
- return {};
+std::list<NotifyArgs> GestureConverter::handleFling(nsecs_t when, nsecs_t readTime,
+ const Gesture& gesture) {
+ switch (gesture.details.fling.fling_state) {
+ case GESTURES_FLING_START:
+ if (mCurrentClassification == MotionClassification::TWO_FINGER_SWIPE) {
+ // We don't actually want to use the gestures library's fling velocity values (to
+ // ensure consistency between touchscreen and touchpad flings), so we're just using
+ // the "start fling" gestures as a marker for the end of a two-finger scroll
+ // gesture.
+ return {endScroll(when, readTime)};
+ }
+ break;
+ case GESTURES_FLING_TAP_DOWN:
+ if (mCurrentClassification == MotionClassification::NONE) {
+ // Use the tap down state of a fling gesture as an indicator that a contact
+ // has been initiated with the touchpad. We treat this as a move event with zero
+ // magnitude, which will also result in the pointer icon being updated.
+ // TODO(b/282023644): Add a signal in libgestures for when a stable contact has been
+ // initiated with a touchpad.
+ return {handleMove(when, readTime,
+ Gesture(kGestureMove, gesture.start_time, gesture.end_time,
+ /*dx=*/0.f,
+ /*dy=*/0.f))};
+ }
+ break;
+ default:
+ break;
}
- return endScroll(when, readTime);
+ return {};
}
-NotifyArgs GestureConverter::endScroll(nsecs_t when, nsecs_t readTime) {
+NotifyMotionArgs GestureConverter::endScroll(nsecs_t when, nsecs_t readTime) {
const auto [xCursorPosition, yCursorPosition] = mPointerController->getPosition();
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_X_DISTANCE, 0);
mFakeFingerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_GESTURE_SCROLL_Y_DISTANCE, 0);
@@ -507,14 +528,29 @@
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords,
float xCursorPosition, float yCursorPosition) {
- return NotifyMotionArgs(mReaderContext.getNextId(), when, readTime, mDeviceId, SOURCE,
- mPointerController->getDisplayId(), /* policyFlags= */ POLICY_FLAG_WAKE,
- action, /* actionButton= */ actionButton, /* flags= */ 0,
- mReaderContext.getGlobalMetaState(), buttonState,
- mCurrentClassification, AMOTION_EVENT_EDGE_FLAG_NONE, pointerCount,
- pointerProperties, pointerCoords, /* xPrecision= */ 1.0f,
- /* yPrecision= */ 1.0f, xCursorPosition, yCursorPosition,
- /* downTime= */ mDownTime, /* videoFrames= */ {});
+ return {mReaderContext.getNextId(),
+ when,
+ readTime,
+ mDeviceId,
+ SOURCE,
+ mPointerController->getDisplayId(),
+ /* policyFlags= */ POLICY_FLAG_WAKE,
+ action,
+ /* actionButton= */ actionButton,
+ /* flags= */ 0,
+ mReaderContext.getGlobalMetaState(),
+ buttonState,
+ mCurrentClassification,
+ AMOTION_EVENT_EDGE_FLAG_NONE,
+ pointerCount,
+ pointerProperties,
+ pointerCoords,
+ /* xPrecision= */ 1.0f,
+ /* yPrecision= */ 1.0f,
+ xCursorPosition,
+ yCursorPosition,
+ /* downTime= */ mDownTime,
+ /* videoFrames= */ {}};
}
} // namespace android
diff --git a/services/inputflinger/reader/mapper/gestures/GestureConverter.h b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
index 70e8fb7..b613b88 100644
--- a/services/inputflinger/reader/mapper/gestures/GestureConverter.h
+++ b/services/inputflinger/reader/mapper/gestures/GestureConverter.h
@@ -52,14 +52,16 @@
const Gesture& gesture);
private:
- [[nodiscard]] NotifyArgs handleMove(nsecs_t when, nsecs_t readTime, const Gesture& gesture);
+ [[nodiscard]] NotifyMotionArgs handleMove(nsecs_t when, nsecs_t readTime,
+ const Gesture& gesture);
[[nodiscard]] std::list<NotifyArgs> handleButtonsChange(nsecs_t when, nsecs_t readTime,
const Gesture& gesture);
[[nodiscard]] std::list<NotifyArgs> releaseAllButtons(nsecs_t when, nsecs_t readTime);
[[nodiscard]] std::list<NotifyArgs> handleScroll(nsecs_t when, nsecs_t readTime,
const Gesture& gesture);
- [[nodiscard]] NotifyArgs handleFling(nsecs_t when, nsecs_t readTime, const Gesture& gesture);
- [[nodiscard]] NotifyArgs endScroll(nsecs_t when, nsecs_t readTime);
+ [[nodiscard]] std::list<NotifyArgs> handleFling(nsecs_t when, nsecs_t readTime,
+ const Gesture& gesture);
+ [[nodiscard]] NotifyMotionArgs endScroll(nsecs_t when, nsecs_t readTime);
[[nodiscard]] std::list<NotifyArgs> handleMultiFingerSwipe(nsecs_t when, nsecs_t readTime,
uint32_t fingerCount, float dx,
diff --git a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
index 3dc5152..99a6a1f 100644
--- a/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
+++ b/services/inputflinger/tests/CapturedTouchpadEventConverter_test.cpp
@@ -781,4 +781,175 @@
WithPointerId(/*index=*/1, /*id=*/0)));
}
+// Motion events without any pointers are invalid, so when a button press is reported in the same
+// frame as a touch down, the button press must be reported second. Similarly with a button release
+// and a touch lift.
+TEST_F(CapturedTouchpadEventConverterTest,
+ ButtonPressedAndReleasedInSameFrameAsTouch_ReportedWithPointers) {
+ CapturedTouchpadEventConverter conv = createConverter();
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
+
+ processAxis(conv, EV_KEY, BTN_LEFT, 1);
+
+ std::list<NotifyArgs> args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithPointerCount(1u),
+ WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)));
+
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 0);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
+
+ processAxis(conv, EV_KEY, BTN_LEFT, 0);
+ args = processSync(conv);
+ ASSERT_EQ(3u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithPointerCount(1u),
+ WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(0)));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_UP));
+}
+
+// Some touchpads sometimes report a button press before they report the finger touching the pad. In
+// that case we need to wait until the touch comes to report the button press.
+TEST_F(CapturedTouchpadEventConverterTest, ButtonPressedBeforeTouch_ReportedOnceTouchOccurs) {
+ CapturedTouchpadEventConverter conv = createConverter();
+
+ processAxis(conv, EV_KEY, BTN_LEFT, 1);
+ ASSERT_EQ(0u, processSync(conv).size());
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
+
+ std::list<NotifyArgs> args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS), WithPointerCount(1u),
+ WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)));
+}
+
+// When all fingers are lifted from a touchpad, we should release any buttons that are down, since
+// we won't be able to report them being lifted later if no pointers are present.
+TEST_F(CapturedTouchpadEventConverterTest, ButtonReleasedAfterTouchLifts_ReportedWithLift) {
+ CapturedTouchpadEventConverter conv = createConverter();
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
+
+ processAxis(conv, EV_KEY, BTN_LEFT, 1);
+
+ std::list<NotifyArgs> args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS));
+
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 0);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 0);
+ args = processSync(conv);
+ ASSERT_EQ(3u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE), WithPointerCount(1u),
+ WithCoords(50, 100), WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(0)));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_UP));
+
+ processAxis(conv, EV_KEY, BTN_LEFT, 0);
+ ASSERT_EQ(0u, processSync(conv).size());
+}
+
+TEST_F(CapturedTouchpadEventConverterTest, MultipleButtonsPressedDuringTouch_ReportedCorrectly) {
+ CapturedTouchpadEventConverter conv = createConverter();
+
+ processAxis(conv, EV_ABS, ABS_MT_SLOT, 0);
+ processAxis(conv, EV_ABS, ABS_MT_TRACKING_ID, 1);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_X, 50);
+ processAxis(conv, EV_ABS, ABS_MT_POSITION_Y, 100);
+ processAxis(conv, EV_KEY, BTN_TOUCH, 1);
+ processAxis(conv, EV_KEY, BTN_TOOL_FINGER, 1);
+
+ EXPECT_THAT(processSyncAndExpectSingleMotionArg(conv),
+ WithMotionAction(AMOTION_EVENT_ACTION_DOWN));
+
+ processAxis(conv, EV_KEY, BTN_LEFT, 1);
+ std::list<NotifyArgs> args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
+ WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY)));
+
+ processAxis(conv, EV_KEY, BTN_RIGHT, 1);
+ args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_PRESS),
+ WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY),
+ WithButtonState(AMOTION_EVENT_BUTTON_PRIMARY |
+ AMOTION_EVENT_BUTTON_SECONDARY)));
+
+ processAxis(conv, EV_KEY, BTN_LEFT, 0);
+ args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
+ WithActionButton(AMOTION_EVENT_BUTTON_PRIMARY),
+ WithButtonState(AMOTION_EVENT_BUTTON_SECONDARY)));
+
+ processAxis(conv, EV_KEY, BTN_RIGHT, 0);
+ args = processSync(conv);
+ ASSERT_EQ(2u, args.size());
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ WithMotionAction(AMOTION_EVENT_ACTION_MOVE));
+ args.pop_front();
+ EXPECT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_BUTTON_RELEASE),
+ WithActionButton(AMOTION_EVENT_BUTTON_SECONDARY), WithButtonState(0)));
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/GestureConverter_test.cpp b/services/inputflinger/tests/GestureConverter_test.cpp
index c6d541e..a723636 100644
--- a/services/inputflinger/tests/GestureConverter_test.cpp
+++ b/services/inputflinger/tests/GestureConverter_test.cpp
@@ -888,4 +888,21 @@
WithToolType(ToolType::FINGER)));
}
+TEST_F(GestureConverterTest, FlingTapDown) {
+ InputDeviceContext deviceContext(*mDevice, EVENTHUB_ID);
+ GestureConverter converter(*mReader->getContext(), deviceContext, DEVICE_ID);
+
+ Gesture tapDownGesture(kGestureFling, ARBITRARY_GESTURE_TIME, ARBITRARY_GESTURE_TIME,
+ /*vx=*/0.f, /*vy=*/0.f, GESTURES_FLING_TAP_DOWN);
+ std::list<NotifyArgs> args = converter.handleGesture(ARBITRARY_TIME, READ_TIME, tapDownGesture);
+
+ ASSERT_THAT(std::get<NotifyMotionArgs>(args.front()),
+ AllOf(WithMotionAction(AMOTION_EVENT_ACTION_HOVER_MOVE),
+ WithCoords(POINTER_X, POINTER_Y), WithRelativeMotion(0.f, 0.f),
+ WithToolType(ToolType::FINGER), WithButtonState(0), WithPressure(0.0f)));
+
+ ASSERT_NO_FATAL_FAILURE(mFakePointerController->assertPosition(POINTER_X, POINTER_Y));
+ ASSERT_TRUE(mFakePointerController->isPointerShown());
+}
+
} // namespace android
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index f6f02d8..fecd0d1 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -86,6 +86,8 @@
AMOTION_EVENT_ACTION_POINTER_UP | (0 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
static constexpr int32_t POINTER_1_UP =
AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+static constexpr int32_t POINTER_2_UP =
+ AMOTION_EVENT_ACTION_POINTER_UP | (2 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
// The default pid and uid for windows created on the primary display by the test.
static constexpr int32_t WINDOW_PID = 999;
@@ -1660,6 +1662,11 @@
return *this;
}
+ MotionArgsBuilder& classification(MotionClassification classification) {
+ mClassification = classification;
+ return *this;
+ }
+
NotifyMotionArgs build() {
std::vector<PointerProperties> pointerProperties;
std::vector<PointerCoords> pointerCoords;
@@ -1678,7 +1685,7 @@
NotifyMotionArgs args(InputEvent::nextId(), mEventTime, /*readTime=*/mEventTime, mDeviceId,
mSource, mDisplayId, mPolicyFlags, mAction, mActionButton, mFlags,
- AMETA_NONE, mButtonState, MotionClassification::NONE, /*edgeFlags=*/0,
+ AMETA_NONE, mButtonState, mClassification, /*edgeFlags=*/0,
mPointers.size(), pointerProperties.data(), pointerCoords.data(),
/*xPrecision=*/0, /*yPrecision=*/0, mRawXCursorPosition,
mRawYCursorPosition, mDownTime, /*videoFrames=*/{});
@@ -1697,6 +1704,7 @@
int32_t mActionButton{0};
int32_t mButtonState{0};
int32_t mFlags{0};
+ MotionClassification mClassification{MotionClassification::NONE};
float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
@@ -4003,6 +4011,126 @@
EXPECT_EQ(-10, event->getY(1)); // -50 + 40
}
+TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeOnlySentToTrustedOverlays) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 400, 400));
+ sp<FakeWindowHandle> trustedOverlay =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Trusted Overlay",
+ ADISPLAY_ID_DEFAULT);
+ trustedOverlay->setSpy(true);
+ trustedOverlay->setTrustedOverlay(true);
+
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {trustedOverlay, window}}});
+
+ // Start a three-finger touchpad swipe
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
+ .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+
+ trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_DOWN));
+ trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_DOWN));
+ trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_DOWN));
+
+ // Move the swipe a bit
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
+ .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+
+ trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_MOVE));
+
+ // End the swipe
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
+ .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+
+ trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_2_UP));
+ trustedOverlay->consumeMotionEvent(WithMotionAction(POINTER_1_UP));
+ trustedOverlay->consumeMotionEvent(WithMotionAction(ACTION_UP));
+
+ window->assertNoEvents();
+}
+
+TEST_F(InputDispatcherTest, TouchpadThreeFingerSwipeNotSentToSingleWindow) {
+ std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+ sp<FakeWindowHandle> window =
+ sp<FakeWindowHandle>::make(application, mDispatcher, "Window", ADISPLAY_ID_DEFAULT);
+ window->setFrame(Rect(0, 0, 400, 400));
+ mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
+
+ // Start a three-finger touchpad swipe
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_DOWN, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_DOWN, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_DOWN, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(100))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(100))
+ .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(100))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+
+ // Move the swipe a bit
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_MOVE, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
+ .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+
+ // End the swipe
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_2_UP, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
+ .pointer(PointerBuilder(2, ToolType::FINGER).x(300).y(105))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+ mDispatcher->notifyMotion(MotionArgsBuilder(POINTER_1_UP, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
+ .pointer(PointerBuilder(1, ToolType::FINGER).x(250).y(105))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+ mDispatcher->notifyMotion(MotionArgsBuilder(ACTION_UP, AINPUT_SOURCE_MOUSE)
+ .pointer(PointerBuilder(0, ToolType::FINGER).x(200).y(105))
+ .classification(MotionClassification::MULTI_FINGER_SWIPE)
+ .build());
+
+ window->assertNoEvents();
+}
+
/**
* Ensure the correct coordinate spaces are used by InputDispatcher.
*
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 20f4de1..f6ca9e2 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -50,8 +50,6 @@
namespace hal = hardware::graphics::composer::hal;
-ui::Transform::RotationFlags DisplayDevice::sPrimaryDisplayRotationFlags = ui::Transform::ROT_0;
-
DisplayDeviceCreationArgs::DisplayDeviceCreationArgs(
const sp<SurfaceFlinger>& flinger, HWComposer& hwComposer, const wp<IBinder>& displayToken,
std::shared_ptr<compositionengine::Display> compositionDisplay)
@@ -282,10 +280,6 @@
Rect orientedDisplaySpaceRect) {
mOrientation = orientation;
- if (isPrimary()) {
- sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
- }
-
// We need to take care of display rotation for globalTransform for case if the panel is not
// installed aligned with device orientation.
const auto transformOrientation = orientation + mPhysicalOrientation;
@@ -326,10 +320,6 @@
return mStagedBrightness;
}
-ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
- return sPrimaryDisplayRotationFlags;
-}
-
void DisplayDevice::dump(utils::Dumper& dumper) const {
using namespace std::string_view_literals;
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 51876e7..dc5f8a8 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -109,8 +109,6 @@
ui::Rotation getPhysicalOrientation() const { return mPhysicalOrientation; }
ui::Rotation getOrientation() const { return mOrientation; }
- static ui::Transform::RotationFlags getPrimaryDisplayRotationFlags();
-
std::optional<float> getStagedBrightness() const REQUIRES(kMainThreadContext);
ui::Transform::RotationFlags getTransformHint() const;
const ui::Transform& getTransform() const;
@@ -274,8 +272,6 @@
const ui::Rotation mPhysicalOrientation;
ui::Rotation mOrientation = ui::ROTATION_0;
- static ui::Transform::RotationFlags sPrimaryDisplayRotationFlags;
-
// Allow nullopt as initial power mode.
using TracedPowerMode = TracedOrdinal<hardware::graphics::composer::hal::PowerMode>;
std::optional<TracedPowerMode> mPowerMode;
diff --git a/services/surfaceflinger/FrontEnd/DisplayInfo.h b/services/surfaceflinger/FrontEnd/DisplayInfo.h
index 76b36fe..218a64a 100644
--- a/services/surfaceflinger/FrontEnd/DisplayInfo.h
+++ b/services/surfaceflinger/FrontEnd/DisplayInfo.h
@@ -28,7 +28,7 @@
ui::Transform transform;
bool receivesInput;
bool isSecure;
- // TODO(b/238781169) can eliminate once sPrimaryDisplayRotationFlags is removed.
+ // TODO(b/259407931): can eliminate once SurfaceFlinger::sActiveDisplayRotationFlags is removed.
bool isPrimary;
bool isVirtual;
ui::Transform::RotationFlags rotationFlags;
diff --git a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
index ce7d37e..985c6f9 100644
--- a/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
+++ b/services/surfaceflinger/FrontEnd/LayerSnapshotBuilder.cpp
@@ -667,6 +667,7 @@
snapshot.relativeLayerMetadata.mMap.clear();
}
+// TODO (b/259407931): Remove.
uint32_t getPrimaryDisplayRotationFlags(
const display::DisplayMap<ui::LayerStack, frontend::DisplayInfo>& displays) {
for (auto& [_, display] : displays) {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a821466..f12aab7 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -254,7 +254,8 @@
mFlinger->mTunnelModeEnabledReporter->decrementTunnelModeCount();
}
if (mHadClonedChild) {
- mFlinger->mNumClones--;
+ auto& roots = mFlinger->mLayerMirrorRoots;
+ roots.erase(std::remove(roots.begin(), roots.end(), this), roots.end());
}
if (hasTrustedPresentationListener()) {
mFlinger->mNumTrustedPresentationListeners--;
@@ -1649,8 +1650,8 @@
void Layer::dumpOffscreenDebugInfo(std::string& result) const {
std::string hasBuffer = hasBufferOrSidebandStream() ? " (contains buffer)" : "";
- StringAppendF(&result, "Layer %s%s pid:%d uid:%d\n", getName().c_str(), hasBuffer.c_str(),
- mOwnerPid, mOwnerUid);
+ StringAppendF(&result, "Layer %s%s pid:%d uid:%d%s\n", getName().c_str(), hasBuffer.c_str(),
+ mOwnerPid, mOwnerUid, isHandleAlive() ? " handleAlive" : "");
}
void Layer::onDisconnect() {
@@ -2594,7 +2595,7 @@
mDrawingState.inputInfo = tmpInputInfo;
}
-void Layer::updateMirrorInfo() {
+bool Layer::updateMirrorInfo(const std::deque<Layer*>& cloneRootsPendingUpdates) {
if (mClonedChild == nullptr || !mClonedChild->isClonedFromAlive()) {
// If mClonedChild is null, there is nothing to mirror. If isClonedFromAlive returns false,
// it means that there is a clone, but the layer it was cloned from has been destroyed. In
@@ -2602,7 +2603,7 @@
// destroyed. The root, this layer, will still be around since the client can continue
// to hold a reference, but no cloned layers will be displayed.
mClonedChild = nullptr;
- return;
+ return true;
}
std::map<sp<Layer>, sp<Layer>> clonedLayersMap;
@@ -2617,6 +2618,13 @@
mClonedChild->updateClonedDrawingState(clonedLayersMap);
mClonedChild->updateClonedChildren(sp<Layer>::fromExisting(this), clonedLayersMap);
mClonedChild->updateClonedRelatives(clonedLayersMap);
+
+ for (Layer* root : cloneRootsPendingUpdates) {
+ if (clonedLayersMap.find(sp<Layer>::fromExisting(root)) != clonedLayersMap.end()) {
+ return false;
+ }
+ }
+ return true;
}
void Layer::updateClonedDrawingState(std::map<sp<Layer>, sp<Layer>>& clonedLayersMap) {
@@ -2764,7 +2772,7 @@
void Layer::setClonedChild(const sp<Layer>& clonedChild) {
mClonedChild = clonedChild;
mHadClonedChild = true;
- mFlinger->mNumClones++;
+ mFlinger->mLayerMirrorRoots.push_back(this);
}
bool Layer::setDropInputMode(gui::DropInputMode mode) {
@@ -2977,7 +2985,7 @@
if (mDrawingState.bufferTransform & ui::Transform::ROT_90) {
std::swap(bufferWidth, bufferHeight);
}
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ uint32_t invTransform = SurfaceFlinger::getActiveDisplayRotationFlags();
if (mDrawingState.transformToDisplayInverse) {
if (invTransform & ui::Transform::ROT_90) {
std::swap(bufferWidth, bufferHeight);
@@ -3304,7 +3312,7 @@
}
if (getTransformToDisplayInverse()) {
- uint32_t invTransform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ uint32_t invTransform = SurfaceFlinger::getActiveDisplayRotationFlags();
if (invTransform & ui::Transform::ROT_90) {
std::swap(bufWidth, bufHeight);
}
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index a6c70e5..38590e6 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -652,7 +652,7 @@
gui::WindowInfo::Type getWindowType() const { return mWindowType; }
- void updateMirrorInfo();
+ bool updateMirrorInfo(const std::deque<Layer*>& cloneRootsPendingUpdates);
/*
* doTransaction - process the transaction. This is a good place to figure
diff --git a/services/surfaceflinger/LayerFE.cpp b/services/surfaceflinger/LayerFE.cpp
index e713263..f855f27 100644
--- a/services/surfaceflinger/LayerFE.cpp
+++ b/services/surfaceflinger/LayerFE.cpp
@@ -25,8 +25,8 @@
#include <system/window.h>
#include <utils/Log.h>
-#include "DisplayDevice.h"
#include "LayerFE.h"
+#include "SurfaceFlinger.h"
namespace android {
@@ -260,7 +260,7 @@
* the code below applies the primary display's inverse transform to
* the texture transform
*/
- uint32_t transform = DisplayDevice::getPrimaryDisplayRotationFlags();
+ uint32_t transform = SurfaceFlinger::getActiveDisplayRotationFlags();
mat4 tr = inverseOrientation(transform);
/**
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
index f6b5afc..d606cff 100644
--- a/services/surfaceflinger/LayerRenderArea.cpp
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -85,7 +85,7 @@
// If layer is offscreen, update mirroring info if it exists
if (mLayer->isRemovedFromCurrentState()) {
mLayer->traverse(LayerVector::StateSet::Drawing,
- [&](Layer* layer) { layer->updateMirrorInfo(); });
+ [&](Layer* layer) { layer->updateMirrorInfo({}); });
mLayer->traverse(LayerVector::StateSet::Drawing,
[&](Layer* layer) { layer->updateCloneBufferInfo(); });
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 06ac8cb..d55ec99 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -356,6 +356,8 @@
PermissionCache::checkPermission(permission, pid, uid);
}
+ui::Transform::RotationFlags SurfaceFlinger::sActiveDisplayRotationFlags = ui::Transform::ROT_0;
+
SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
: mFactory(factory),
mPid(getpid()),
@@ -2619,7 +2621,7 @@
refreshArgs.updatingOutputGeometryThisFrame = mVisibleRegionsDirty;
refreshArgs.updatingGeometryThisFrame = mGeometryDirty.exchange(false) || mVisibleRegionsDirty;
- refreshArgs.internalDisplayRotationFlags = DisplayDevice::getPrimaryDisplayRotationFlags();
+ refreshArgs.internalDisplayRotationFlags = getActiveDisplayRotationFlags();
if (CC_UNLIKELY(mDrawingState.colorMatrixChanged)) {
refreshArgs.colorTransformMatrix = mDrawingState.colorMatrix;
@@ -3563,6 +3565,8 @@
currentState.orientedDisplaySpaceRect);
if (display->getId() == mActiveDisplayId) {
mActiveDisplayTransformHint = display->getTransformHint();
+ sActiveDisplayRotationFlags =
+ ui::Transform::toRotationFlags(display->getOrientation());
}
}
if (currentState.width != drawingState.width ||
@@ -4025,8 +4029,24 @@
}
commitOffscreenLayers();
- if (mNumClones > 0) {
- mDrawingState.traverse([&](Layer* layer) { layer->updateMirrorInfo(); });
+ if (mLayerMirrorRoots.size() > 0) {
+ std::deque<Layer*> pendingUpdates;
+ pendingUpdates.insert(pendingUpdates.end(), mLayerMirrorRoots.begin(),
+ mLayerMirrorRoots.end());
+ std::vector<Layer*> needsUpdating;
+ for (Layer* cloneRoot : mLayerMirrorRoots) {
+ pendingUpdates.pop_front();
+ if (cloneRoot->isRemovedFromCurrentState()) {
+ continue;
+ }
+ if (cloneRoot->updateMirrorInfo(pendingUpdates)) {
+ } else {
+ needsUpdating.push_back(cloneRoot);
+ }
+ }
+ for (Layer* cloneRoot : needsUpdating) {
+ cloneRoot->updateMirrorInfo({});
+ }
}
}
@@ -4133,7 +4153,7 @@
mBootStage = BootStage::BOOTANIMATION;
}
- if (mNumClones > 0) {
+ if (mLayerMirrorRoots.size() > 0) {
mDrawingState.traverse([&](Layer* layer) { layer->updateCloneBufferInfo(); });
}
@@ -4158,8 +4178,8 @@
leakingParentLayerFound = true;
sp<Layer> parent = sp<Layer>::fromExisting(layer);
while (parent) {
- ALOGE("Parent Layer: %s handleIsAlive: %s", parent->getName().c_str(),
- std::to_string(parent->isHandleAlive()).c_str());
+ ALOGE("Parent Layer: %s%s", parent->getName().c_str(),
+ (parent->isHandleAlive() ? "handleAlive" : ""));
parent = parent->getParent();
}
// Sample up to 100 layers
@@ -4174,21 +4194,28 @@
}
});
- ALOGE("Dumping random sampling of on-screen layers: ");
+ int numLayers = 0;
+ mDrawingState.traverse([&](Layer* layer) { numLayers++; });
+
+ ALOGE("Dumping random sampling of on-screen layers total(%u):", numLayers);
mDrawingState.traverse([&](Layer* layer) {
// Aim to dump about 200 layers to avoid totally trashing
// logcat. On the other hand, if there really are 4096 layers
// something has gone totally wrong its probably the most
// useful information in logcat.
if (rand() % 20 == 13) {
- ALOGE("Layer: %s", layer->getName().c_str());
+ ALOGE("Layer: %s%s", layer->getName().c_str(),
+ (layer->isHandleAlive() ? "handleAlive" : ""));
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
});
ALOGE("Dumping random sampling of off-screen layers total(%zu): ",
mOffscreenLayers.size());
for (Layer* offscreenLayer : mOffscreenLayers) {
if (rand() % 20 == 13) {
- ALOGE("Offscreen-layer: %s", offscreenLayer->getName().c_str());
+ ALOGE("Offscreen-layer: %s%s", offscreenLayer->getName().c_str(),
+ (offscreenLayer->isHandleAlive() ? "handleAlive" : ""));
+ std::this_thread::sleep_for(std::chrono::milliseconds(5));
}
}
}));
@@ -4474,7 +4501,8 @@
const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
InputWindowCommands inputWindowCommands, int64_t desiredPresentTime, bool isAutoTimestamp,
const std::vector<client_cache_t>& uncacheBuffers, bool hasListenerCallbacks,
- const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId) {
+ const std::vector<ListenerCallbacks>& listenerCallbacks, uint64_t transactionId,
+ const std::vector<uint64_t>& mergedTransactionIds) {
ATRACE_CALL();
IPCThreadState* ipc = IPCThreadState::self();
@@ -4563,7 +4591,8 @@
listenerCallbacks,
originPid,
originUid,
- transactionId};
+ transactionId,
+ mergedTransactionIds};
if (mTransactionTracing) {
mTransactionTracing->addQueuedTransaction(state);
@@ -7954,6 +7983,7 @@
onActiveDisplaySizeChanged(activeDisplay);
mActiveDisplayTransformHint = activeDisplay.getTransformHint();
+ sActiveDisplayRotationFlags = ui::Transform::toRotationFlags(activeDisplay.getOrientation());
// The policy of the new active/pacesetter display may have changed while it was inactive. In
// that case, its preferred mode has not been propagated to HWC (via setDesiredActiveMode). In
@@ -8155,7 +8185,7 @@
});
}
if (mLegacyFrontEndEnabled && !mLayerLifecycleManagerEnabled) {
- mDrawingState.traverseInZOrder([&refreshArgs, cursorOnly, &layers](Layer* layer) {
+ auto moveSnapshots = [&layers, &refreshArgs, cursorOnly](Layer* layer) {
if (const auto& layerFE = layer->getCompositionEngineLayerFE()) {
if (cursorOnly &&
layer->getLayerSnapshot()->compositionType !=
@@ -8166,7 +8196,22 @@
refreshArgs.layers.push_back(layerFE);
layers.emplace_back(layer, layerFE.get());
}
- });
+ };
+
+ if (cursorOnly || !mVisibleRegionsDirty) {
+ // for hot path avoid traversals by walking though the previous composition list
+ for (sp<Layer> layer : mPreviouslyComposedLayers) {
+ moveSnapshots(layer.get());
+ }
+ } else {
+ mPreviouslyComposedLayers.clear();
+ mDrawingState.traverseInZOrder(
+ [&moveSnapshots](Layer* layer) { moveSnapshots(layer); });
+ mPreviouslyComposedLayers.reserve(layers.size());
+ for (auto [layer, _] : layers) {
+ mPreviouslyComposedLayers.push_back(sp<Layer>::fromExisting(layer));
+ }
+ }
}
return layers;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index d92ec7a..e2691ab 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -296,8 +296,7 @@
// the client can no longer modify this layer directly.
void onHandleDestroyed(BBinder* handle, sp<Layer>& layer, uint32_t layerId);
- // TODO: Remove atomic if move dtor to main thread CL lands
- std::atomic<uint32_t> mNumClones;
+ std::vector<Layer*> mLayerMirrorRoots;
TransactionCallbackInvoker& getTransactionCallbackInvoker() {
return mTransactionCallbackInvoker;
@@ -332,6 +331,14 @@
const DisplayDevice* getDisplayFromLayerStack(ui::LayerStack)
REQUIRES(mStateLock, kMainThreadContext);
+ // TODO (b/259407931): Remove.
+ // TODO (b/281857977): This should be annotated with REQUIRES(kMainThreadContext), but this
+ // would require thread safety annotations throughout the frontend (in particular Layer and
+ // LayerFE).
+ static ui::Transform::RotationFlags getActiveDisplayRotationFlags() {
+ return sActiveDisplayRotationFlags;
+ }
+
protected:
// We're reference counted, never destroy SurfaceFlinger directly
virtual ~SurfaceFlinger();
@@ -508,15 +515,13 @@
}
sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const;
- status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
- Vector<ComposerState>& state, const Vector<DisplayState>& displays,
- uint32_t flags, const sp<IBinder>& applyToken,
- InputWindowCommands inputWindowCommands,
- int64_t desiredPresentTime, bool isAutoTimestamp,
- const std::vector<client_cache_t>& uncacheBuffers,
- bool hasListenerCallbacks,
- const std::vector<ListenerCallbacks>& listenerCallbacks,
- uint64_t transactionId) override;
+ status_t setTransactionState(
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& state,
+ const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ InputWindowCommands inputWindowCommands, int64_t desiredPresentTime,
+ bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers,
+ bool hasListenerCallbacks, const std::vector<ListenerCallbacks>& listenerCallbacks,
+ uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) override;
void bootFinished();
virtual status_t getSupportedFrameTimestamps(std::vector<FrameEvent>* outSupported) const;
sp<IDisplayEventConnection> createDisplayEventConnection(
@@ -1199,6 +1204,11 @@
std::unordered_set<sp<Layer>, SpHash<Layer>> mLayersWithBuffersRemoved;
// Tracks layers that need to update a display's dirty region.
std::vector<sp<Layer>> mLayersPendingRefresh;
+ // Sorted list of layers that were composed during previous frame. This is used to
+ // avoid an expensive traversal of the layer hierarchy when there are no
+ // visible region changes. Because this is a list of strong pointers, this will
+ // extend the life of the layer but this list is only updated in the main thread.
+ std::vector<sp<Layer>> mPreviouslyComposedLayers;
BootStage mBootStage = BootStage::BOOTLOADER;
@@ -1390,6 +1400,10 @@
std::atomic<ui::Transform::RotationFlags> mActiveDisplayTransformHint;
+ // Must only be accessed on the main thread.
+ // TODO (b/259407931): Remove.
+ static ui::Transform::RotationFlags sActiveDisplayRotationFlags;
+
bool isRefreshRateOverlayEnabled() const REQUIRES(mStateLock) {
return hasDisplay(
[](const auto& display) { return display.isRefreshRateOverlayEnabled(); });
diff --git a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
index 57d927b..0694180 100644
--- a/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
+++ b/services/surfaceflinger/Tracing/TransactionProtoParser.cpp
@@ -69,6 +69,13 @@
for (auto& displayState : t.displays) {
proto.mutable_display_changes()->Add(std::move(toProto(displayState)));
}
+
+ proto.mutable_merged_transaction_ids()->Reserve(
+ static_cast<int32_t>(t.mergedTransactionIds.size()));
+ for (auto& mergedTransactionId : t.mergedTransactionIds) {
+ proto.mutable_merged_transaction_ids()->Add(mergedTransactionId);
+ }
+
return proto;
}
diff --git a/services/surfaceflinger/TransactionState.h b/services/surfaceflinger/TransactionState.h
index 62a7dfd..7132a59 100644
--- a/services/surfaceflinger/TransactionState.h
+++ b/services/surfaceflinger/TransactionState.h
@@ -56,7 +56,8 @@
int64_t desiredPresentTime, bool isAutoTimestamp,
std::vector<uint64_t> uncacheBufferIds, int64_t postTime,
bool hasListenerCallbacks, std::vector<ListenerCallbacks> listenerCallbacks,
- int originPid, int originUid, uint64_t transactionId)
+ int originPid, int originUid, uint64_t transactionId,
+ std::vector<uint64_t> mergedTransactionIds)
: frameTimelineInfo(frameTimelineInfo),
states(std::move(composerStates)),
displays(displayStates),
@@ -71,7 +72,8 @@
listenerCallbacks(listenerCallbacks),
originPid(originPid),
originUid(originUid),
- id(transactionId) {}
+ id(transactionId),
+ mergedTransactionIds(std::move(mergedTransactionIds)) {}
// Invokes `void(const layer_state_t&)` visitor for matching layers.
template <typename Visitor>
@@ -131,6 +133,7 @@
int originUid;
uint64_t id;
bool sentFenceTimeoutWarning = false;
+ std::vector<uint64_t> mergedTransactionIds;
};
} // namespace android
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index ce4d18f..80943b5 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -185,11 +185,12 @@
bool hasListenerCallbacks = mFdp.ConsumeBool();
std::vector<ListenerCallbacks> listenerCallbacks{};
uint64_t transactionId = mFdp.ConsumeIntegral<uint64_t>();
+ std::vector<uint64_t> mergedTransactionIds{};
mTestableFlinger.setTransactionState(FrameTimelineInfo{}, states, displays, flags, applyToken,
InputWindowCommands{}, desiredPresentTime, isAutoTimestamp,
- {}, hasListenerCallbacks, listenerCallbacks,
- transactionId);
+ {}, hasListenerCallbacks, listenerCallbacks, transactionId,
+ mergedTransactionIds);
}
void SurfaceFlingerFuzzer::setDisplayStateLocked() {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 4d13aca..da5ec48 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -737,19 +737,18 @@
return mFlinger->mTransactionHandler.mPendingTransactionQueues;
}
- auto setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
- Vector<ComposerState>& states, const Vector<DisplayState>& displays,
- uint32_t flags, const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands,
- int64_t desiredPresentTime, bool isAutoTimestamp,
- const std::vector<client_cache_t>& uncacheBuffers,
- bool hasListenerCallbacks,
- std::vector<ListenerCallbacks>& listenerCallbacks,
- uint64_t transactionId) {
+ auto setTransactionState(
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states,
+ const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
+ bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers,
+ bool hasListenerCallbacks, std::vector<ListenerCallbacks>& listenerCallbacks,
+ uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) {
return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken,
inputWindowCommands, desiredPresentTime,
isAutoTimestamp, uncacheBuffers, hasListenerCallbacks,
- listenerCallbacks, transactionId);
+ listenerCallbacks, transactionId,
+ mergedTransactionIds);
}
auto flushTransactionQueues() {
diff --git a/services/surfaceflinger/layerproto/transactions.proto b/services/surfaceflinger/layerproto/transactions.proto
index 2c4eb10..b0cee9b 100644
--- a/services/surfaceflinger/layerproto/transactions.proto
+++ b/services/surfaceflinger/layerproto/transactions.proto
@@ -100,6 +100,7 @@
uint64 transaction_id = 6;
repeated LayerState layer_changes = 7;
repeated DisplayState display_changes = 8;
+ repeated uint64 merged_transaction_ids = 9;
}
// Keep insync with layer_state_t
diff --git a/services/surfaceflinger/tests/unittests/ActiveDisplayRotationFlagsTest.cpp b/services/surfaceflinger/tests/unittests/ActiveDisplayRotationFlagsTest.cpp
new file mode 100644
index 0000000..7077523
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/ActiveDisplayRotationFlagsTest.cpp
@@ -0,0 +1,148 @@
+/*
+ * Copyright 2023 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "LibSurfaceFlingerUnittests"
+
+#include "DisplayTransactionTestHelpers.h"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace android {
+namespace {
+
+struct ActiveDisplayRotationFlagsTest : DisplayTransactionTest {
+ static constexpr bool kWithMockScheduler = false;
+ ActiveDisplayRotationFlagsTest() : DisplayTransactionTest(kWithMockScheduler) {}
+
+ void SetUp() override {
+ injectMockScheduler(kInnerDisplayId);
+
+ // Inject inner and outer displays with uninitialized power modes.
+ constexpr bool kInitPowerMode = false;
+ {
+ InnerDisplayVariant::injectHwcDisplay<kInitPowerMode>(this);
+ auto injector = InnerDisplayVariant::makeFakeExistingDisplayInjector(this);
+ injector.setPowerMode(std::nullopt);
+ injector.setRefreshRateSelector(mFlinger.scheduler()->refreshRateSelector());
+ mInnerDisplay = injector.inject();
+ }
+ {
+ OuterDisplayVariant::injectHwcDisplay<kInitPowerMode>(this);
+ auto injector = OuterDisplayVariant::makeFakeExistingDisplayInjector(this);
+ injector.setPowerMode(std::nullopt);
+ mOuterDisplay = injector.inject();
+ }
+
+ mFlinger.setPowerModeInternal(mInnerDisplay, PowerMode::ON);
+ mFlinger.setPowerModeInternal(mOuterDisplay, PowerMode::ON);
+
+ // The flags are a static variable, so by modifying them in the test, we
+ // are modifying the real ones used by SurfaceFlinger. Save the original
+ // flags so we can restore them on teardown. This isn't perfect - the
+ // phone may have been rotated during the test, so we're restoring the
+ // wrong flags. But if the phone is rotated, this may also fail the test.
+ mOldRotationFlags = mFlinger.mutableActiveDisplayRotationFlags();
+
+ // Reset to the expected default state.
+ mFlinger.mutableActiveDisplayRotationFlags() = ui::Transform::ROT_0;
+ }
+
+ void TearDown() override { mFlinger.mutableActiveDisplayRotationFlags() = mOldRotationFlags; }
+
+ static inline PhysicalDisplayId kInnerDisplayId = InnerDisplayVariant::DISPLAY_ID::get();
+ static inline PhysicalDisplayId kOuterDisplayId = OuterDisplayVariant::DISPLAY_ID::get();
+
+ sp<DisplayDevice> mInnerDisplay, mOuterDisplay;
+ ui::Transform::RotationFlags mOldRotationFlags;
+};
+
+TEST_F(ActiveDisplayRotationFlagsTest, defaultRotation) {
+ ASSERT_EQ(ui::Transform::ROT_0, SurfaceFlinger::getActiveDisplayRotationFlags());
+}
+
+TEST_F(ActiveDisplayRotationFlagsTest, rotate90) {
+ auto displayToken = mInnerDisplay->getDisplayToken().promote();
+ mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0;
+ mFlinger.mutableCurrentState().displays.editValueFor(displayToken).orientation =
+ ui::ROTATION_90;
+
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
+ ASSERT_EQ(ui::Transform::ROT_90, SurfaceFlinger::getActiveDisplayRotationFlags());
+}
+
+TEST_F(ActiveDisplayRotationFlagsTest, rotate90_inactive) {
+ auto displayToken = mOuterDisplay->getDisplayToken().promote();
+ mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0;
+ mFlinger.mutableCurrentState().displays.editValueFor(displayToken).orientation =
+ ui::ROTATION_90;
+
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
+ ASSERT_EQ(ui::Transform::ROT_0, SurfaceFlinger::getActiveDisplayRotationFlags());
+}
+
+TEST_F(ActiveDisplayRotationFlagsTest, rotateBoth_innerActive) {
+ auto displayToken = mInnerDisplay->getDisplayToken().promote();
+ mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0;
+ mFlinger.mutableCurrentState().displays.editValueFor(displayToken).orientation =
+ ui::ROTATION_180;
+
+ displayToken = mOuterDisplay->getDisplayToken().promote();
+ mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0;
+ mFlinger.mutableCurrentState().displays.editValueFor(displayToken).orientation =
+ ui::ROTATION_270;
+
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
+ ASSERT_EQ(ui::Transform::ROT_180, SurfaceFlinger::getActiveDisplayRotationFlags());
+}
+
+TEST_F(ActiveDisplayRotationFlagsTest, rotateBoth_outerActive) {
+ mFlinger.mutableActiveDisplayId() = kOuterDisplayId;
+ auto displayToken = mInnerDisplay->getDisplayToken().promote();
+ mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0;
+ mFlinger.mutableCurrentState().displays.editValueFor(displayToken).orientation =
+ ui::ROTATION_180;
+
+ displayToken = mOuterDisplay->getDisplayToken().promote();
+ mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0;
+ mFlinger.mutableCurrentState().displays.editValueFor(displayToken).orientation =
+ ui::ROTATION_270;
+
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
+ ASSERT_EQ(ui::Transform::ROT_270, SurfaceFlinger::getActiveDisplayRotationFlags());
+}
+
+TEST_F(ActiveDisplayRotationFlagsTest, onActiveDisplayChanged) {
+ auto displayToken = mInnerDisplay->getDisplayToken().promote();
+ mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0;
+ mFlinger.mutableCurrentState().displays.editValueFor(displayToken).orientation =
+ ui::ROTATION_180;
+
+ displayToken = mOuterDisplay->getDisplayToken().promote();
+ mFlinger.mutableDrawingState().displays.editValueFor(displayToken).orientation = ui::ROTATION_0;
+ mFlinger.mutableCurrentState().displays.editValueFor(displayToken).orientation =
+ ui::ROTATION_270;
+
+ mFlinger.commitTransactionsLocked(eDisplayTransactionNeeded);
+ ASSERT_EQ(ui::Transform::ROT_180, SurfaceFlinger::getActiveDisplayRotationFlags());
+
+ mFlinger.onActiveDisplayChanged(mInnerDisplay.get(), *mOuterDisplay);
+ ASSERT_EQ(ui::Transform::ROT_270, SurfaceFlinger::getActiveDisplayRotationFlags());
+}
+
+} // namespace
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 55705ca..70f8a83 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -70,6 +70,7 @@
":libsurfaceflinger_mock_sources",
":libsurfaceflinger_sources",
"libsurfaceflinger_unittest_main.cpp",
+ "ActiveDisplayRotationFlagsTest.cpp",
"CompositionTest.cpp",
"DisplayIdGeneratorTest.cpp",
"DisplayTransactionTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 6ca21bd..e8a9cfe 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -680,6 +680,9 @@
NativeHandle::create(reinterpret_cast<native_handle_t*>(DEFAULT_SIDEBAND_STREAM),
false);
test->mFlinger.setLayerSidebandStream(layer, stream);
+ auto& layerDrawingState = test->mFlinger.mutableLayerDrawingState(layer);
+ layerDrawingState.crop =
+ Rect(0, 0, SidebandLayerProperties::HEIGHT, SidebandLayerProperties::WIDTH);
}
static void setupHwcSetSourceCropBufferCallExpectations(CompositionTest* test) {
@@ -814,6 +817,7 @@
Mock::VerifyAndClear(test->mComposer);
test->mFlinger.mutableDrawingState().layersSortedByZ.add(layer);
+ test->mFlinger.mutableVisibleRegionsDirty() = true;
}
static void cleanupInjectedLayers(CompositionTest* test) {
@@ -822,6 +826,7 @@
test->mDisplay->getCompositionDisplay()->clearOutputLayers();
test->mFlinger.mutableDrawingState().layersSortedByZ.clear();
+ test->mFlinger.mutablePreviouslyComposedLayers().clear();
// Layer should be unregistered with scheduler.
test->mFlinger.commit();
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index a189c00..945e488 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -466,19 +466,18 @@
return mFlinger->mTransactionHandler.mPendingTransactionCount.load();
}
- auto setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
- Vector<ComposerState>& states, const Vector<DisplayState>& displays,
- uint32_t flags, const sp<IBinder>& applyToken,
- const InputWindowCommands& inputWindowCommands,
- int64_t desiredPresentTime, bool isAutoTimestamp,
- const std::vector<client_cache_t>& uncacheBuffers,
- bool hasListenerCallbacks,
- std::vector<ListenerCallbacks>& listenerCallbacks,
- uint64_t transactionId) {
+ auto setTransactionState(
+ const FrameTimelineInfo& frameTimelineInfo, Vector<ComposerState>& states,
+ const Vector<DisplayState>& displays, uint32_t flags, const sp<IBinder>& applyToken,
+ const InputWindowCommands& inputWindowCommands, int64_t desiredPresentTime,
+ bool isAutoTimestamp, const std::vector<client_cache_t>& uncacheBuffers,
+ bool hasListenerCallbacks, std::vector<ListenerCallbacks>& listenerCallbacks,
+ uint64_t transactionId, const std::vector<uint64_t>& mergedTransactionIds) {
return mFlinger->setTransactionState(frameTimelineInfo, states, displays, flags, applyToken,
inputWindowCommands, desiredPresentTime,
isAutoTimestamp, uncacheBuffers, hasListenerCallbacks,
- listenerCallbacks, transactionId);
+ listenerCallbacks, transactionId,
+ mergedTransactionIds);
}
auto setTransactionStateInternal(TransactionState& transaction) {
@@ -588,6 +587,7 @@
auto& mutablePhysicalDisplays() { return mFlinger->mPhysicalDisplays; }
auto& mutableDrawingState() { return mFlinger->mDrawingState; }
auto& mutableGeometryDirty() { return mFlinger->mGeometryDirty; }
+ auto& mutableVisibleRegionsDirty() { return mFlinger->mVisibleRegionsDirty; }
auto& mutableMainThreadId() { return mFlinger->mMainThreadId; }
auto& mutablePendingHotplugEvents() { return mFlinger->mPendingHotplugEvents; }
auto& mutableTexturePool() { return mFlinger->mTexturePool; }
@@ -599,6 +599,11 @@
auto& mutableHwcPhysicalDisplayIdMap() { return getHwComposer().mPhysicalDisplayIdMap; }
auto& mutablePrimaryHwcDisplayId() { return getHwComposer().mPrimaryHwcDisplayId; }
auto& mutableActiveDisplayId() { return mFlinger->mActiveDisplayId; }
+ auto& mutablePreviouslyComposedLayers() { return mFlinger->mPreviouslyComposedLayers; }
+
+ auto& mutableActiveDisplayRotationFlags() {
+ return SurfaceFlinger::sActiveDisplayRotationFlags;
+ }
auto fromHandle(const sp<IBinder>& handle) { return LayerHandle::getLayer(handle); }
diff --git a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
index 6a641b3..afb8efb 100644
--- a/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionApplicationTest.cpp
@@ -73,6 +73,7 @@
FrameTimelineInfo frameTimelineInfo;
std::vector<client_cache_t> uncacheBuffers;
uint64_t id = static_cast<uint64_t>(-1);
+ std::vector<uint64_t> mergedTransactionIds;
static_assert(0xffffffffffffffff == static_cast<uint64_t>(-1));
};
@@ -108,7 +109,7 @@
transaction.applyToken, transaction.inputWindowCommands,
transaction.desiredPresentTime, transaction.isAutoTimestamp,
transaction.uncacheBuffers, mHasListenerCallbacks, mCallbacks,
- transaction.id);
+ transaction.id, transaction.mergedTransactionIds);
// If transaction is synchronous, SF applyTransactionState should time out (5s) wating for
// SF to commit the transaction. If this is animation, it should not time out waiting.
@@ -135,7 +136,7 @@
transaction.applyToken, transaction.inputWindowCommands,
transaction.desiredPresentTime, transaction.isAutoTimestamp,
transaction.uncacheBuffers, mHasListenerCallbacks, mCallbacks,
- transaction.id);
+ transaction.id, transaction.mergedTransactionIds);
nsecs_t returnedTime = systemTime();
EXPECT_LE(returnedTime, applicationSentTime + TRANSACTION_TIMEOUT);
@@ -166,7 +167,7 @@
transactionA.applyToken, transactionA.inputWindowCommands,
transactionA.desiredPresentTime, transactionA.isAutoTimestamp,
transactionA.uncacheBuffers, mHasListenerCallbacks, mCallbacks,
- transactionA.id);
+ transactionA.id, transactionA.mergedTransactionIds);
// This thread should not have been blocked by the above transaction
// (5s is the timeout period that applyTransactionState waits for SF to
@@ -181,7 +182,7 @@
transactionB.applyToken, transactionB.inputWindowCommands,
transactionB.desiredPresentTime, transactionB.isAutoTimestamp,
transactionB.uncacheBuffers, mHasListenerCallbacks, mCallbacks,
- transactionB.id);
+ transactionB.id, transactionB.mergedTransactionIds);
// this thread should have been blocked by the above transaction
// if this is an animation, this thread should be blocked for 5s
@@ -218,7 +219,8 @@
transactionA.displays, transactionA.flags, transactionA.applyToken,
transactionA.inputWindowCommands, transactionA.desiredPresentTime,
transactionA.isAutoTimestamp, transactionA.uncacheBuffers,
- mHasListenerCallbacks, mCallbacks, transactionA.id);
+ mHasListenerCallbacks, mCallbacks, transactionA.id,
+ transactionA.mergedTransactionIds);
auto& transactionQueue = mFlinger.getTransactionQueue();
ASSERT_FALSE(transactionQueue.isEmpty());
@@ -238,7 +240,8 @@
transactionA.displays, transactionA.flags, transactionA.applyToken,
transactionA.inputWindowCommands, transactionA.desiredPresentTime,
transactionA.isAutoTimestamp, transactionA.uncacheBuffers,
- mHasListenerCallbacks, mCallbacks, transactionA.id);
+ mHasListenerCallbacks, mCallbacks, transactionA.id,
+ transactionA.mergedTransactionIds);
auto& transactionQueue = mFlinger.getTransactionQueue();
ASSERT_FALSE(transactionQueue.isEmpty());
@@ -251,7 +254,8 @@
mFlinger.setTransactionState(empty.frameTimelineInfo, empty.states, empty.displays, empty.flags,
empty.applyToken, empty.inputWindowCommands,
empty.desiredPresentTime, empty.isAutoTimestamp,
- empty.uncacheBuffers, mHasListenerCallbacks, mCallbacks, empty.id);
+ empty.uncacheBuffers, mHasListenerCallbacks, mCallbacks, empty.id,
+ empty.mergedTransactionIds);
// flush transaction queue should flush as desiredPresentTime has
// passed
@@ -388,7 +392,8 @@
transaction.desiredPresentTime,
transaction.isAutoTimestamp, {}, systemTime(),
mHasListenerCallbacks, mCallbacks, getpid(),
- static_cast<int>(getuid()), transaction.id);
+ static_cast<int>(getuid()), transaction.id,
+ transaction.mergedTransactionIds);
mFlinger.setTransactionStateInternal(transactionState);
}
mFlinger.flushTransactionQueues();
@@ -1083,4 +1088,137 @@
EXPECT_EQ(transactionsReadyToBeApplied.front().id, 42u);
}
+TEST(TransactionHandlerTest, TransactionsKeepTrackOfDirectMerges) {
+ SurfaceComposerClient::Transaction transaction1, transaction2, transaction3, transaction4;
+
+ uint64_t transaction2Id = transaction2.getId();
+ uint64_t transaction3Id = transaction3.getId();
+ EXPECT_NE(transaction2Id, transaction3Id);
+
+ transaction1.merge(std::move(transaction2));
+ transaction1.merge(std::move(transaction3));
+
+ EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 2u);
+ EXPECT_EQ(transaction1.getMergedTransactionIds()[0], transaction3Id);
+ EXPECT_EQ(transaction1.getMergedTransactionIds()[1], transaction2Id);
+}
+
+TEST(TransactionHandlerTest, TransactionsKeepTrackOfIndirectMerges) {
+ SurfaceComposerClient::Transaction transaction1, transaction2, transaction3, transaction4;
+
+ uint64_t transaction2Id = transaction2.getId();
+ uint64_t transaction3Id = transaction3.getId();
+ uint64_t transaction4Id = transaction4.getId();
+ EXPECT_NE(transaction2Id, transaction3Id);
+ EXPECT_NE(transaction2Id, transaction4Id);
+ EXPECT_NE(transaction3Id, transaction4Id);
+
+ transaction4.merge(std::move(transaction2));
+ transaction4.merge(std::move(transaction3));
+
+ EXPECT_EQ(transaction4.getMergedTransactionIds().size(), 2u);
+ EXPECT_EQ(transaction4.getMergedTransactionIds()[0], transaction3Id);
+ EXPECT_EQ(transaction4.getMergedTransactionIds()[1], transaction2Id);
+
+ transaction1.merge(std::move(transaction4));
+
+ EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 3u);
+ EXPECT_EQ(transaction1.getMergedTransactionIds()[0], transaction4Id);
+ EXPECT_EQ(transaction1.getMergedTransactionIds()[1], transaction3Id);
+ EXPECT_EQ(transaction1.getMergedTransactionIds()[2], transaction2Id);
+}
+
+TEST(TransactionHandlerTest, TransactionMergesAreCleared) {
+ SurfaceComposerClient::Transaction transaction1, transaction2, transaction3;
+
+ transaction1.merge(std::move(transaction2));
+ transaction1.merge(std::move(transaction3));
+
+ EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 2u);
+
+ transaction1.clear();
+
+ EXPECT_EQ(transaction1.getMergedTransactionIds().empty(), true);
+}
+
+TEST(TransactionHandlerTest, TransactionMergesAreCapped) {
+ SurfaceComposerClient::Transaction transaction;
+ std::vector<uint64_t> mergedTransactionIds;
+
+ for (uint i = 0; i < 20u; i++) {
+ SurfaceComposerClient::Transaction transactionToMerge;
+ mergedTransactionIds.push_back(transactionToMerge.getId());
+ transaction.merge(std::move(transactionToMerge));
+ }
+
+ // Keeps latest 10 merges in order of merge recency
+ EXPECT_EQ(transaction.getMergedTransactionIds().size(), 10u);
+ for (uint i = 0; i < 10u; i++) {
+ EXPECT_EQ(transaction.getMergedTransactionIds()[i],
+ mergedTransactionIds[mergedTransactionIds.size() - 1 - i]);
+ }
+}
+
+TEST(TransactionHandlerTest, KeepsMergesFromMoreRecentMerge) {
+ SurfaceComposerClient::Transaction transaction1, transaction2, transaction3;
+ std::vector<uint64_t> mergedTransactionIds1, mergedTransactionIds2, mergedTransactionIds3;
+ uint64_t transaction2Id = transaction2.getId();
+ uint64_t transaction3Id = transaction3.getId();
+
+ for (uint i = 0; i < 20u; i++) {
+ SurfaceComposerClient::Transaction transactionToMerge;
+ mergedTransactionIds1.push_back(transactionToMerge.getId());
+ transaction1.merge(std::move(transactionToMerge));
+ }
+
+ for (uint i = 0; i < 5u; i++) {
+ SurfaceComposerClient::Transaction transactionToMerge;
+ mergedTransactionIds2.push_back(transactionToMerge.getId());
+ transaction2.merge(std::move(transactionToMerge));
+ }
+
+ transaction1.merge(std::move(transaction2));
+ EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 10u);
+ EXPECT_EQ(transaction1.getMergedTransactionIds()[0], transaction2Id);
+ for (uint i = 0; i < 5u; i++) {
+ EXPECT_EQ(transaction1.getMergedTransactionIds()[i + 1u],
+ mergedTransactionIds2[mergedTransactionIds2.size() - 1 - i]);
+ }
+ for (uint i = 0; i < 4u; i++) {
+ EXPECT_EQ(transaction1.getMergedTransactionIds()[i + 6u],
+ mergedTransactionIds1[mergedTransactionIds1.size() - 1 - i]);
+ }
+
+ for (uint i = 0; i < 20u; i++) {
+ SurfaceComposerClient::Transaction transactionToMerge;
+ mergedTransactionIds3.push_back(transactionToMerge.getId());
+ transaction3.merge(std::move(transactionToMerge));
+ }
+
+ transaction1.merge(std::move(transaction3));
+ EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 10u);
+ EXPECT_EQ(transaction1.getMergedTransactionIds()[0], transaction3Id);
+ for (uint i = 0; i < 9u; i++) {
+ EXPECT_EQ(transaction1.getMergedTransactionIds()[i + 1],
+ mergedTransactionIds3[mergedTransactionIds3.size() - 1 - i]);
+ }
+}
+
+TEST(TransactionHandlerTest, CanAddTransactionWithFullMergedIds) {
+ SurfaceComposerClient::Transaction transaction1, transaction2;
+ for (uint i = 0; i < 20u; i++) {
+ SurfaceComposerClient::Transaction transactionToMerge;
+ transaction1.merge(std::move(transactionToMerge));
+ }
+
+ EXPECT_EQ(transaction1.getMergedTransactionIds().size(), 10u);
+
+ auto transaction1Id = transaction1.getId();
+ transaction2.merge(std::move(transaction1));
+ EXPECT_EQ(transaction2.getMergedTransactionIds().size(), 10u);
+ auto mergedTransactionIds = transaction2.getMergedTransactionIds();
+ EXPECT_TRUE(std::count(mergedTransactionIds.begin(), mergedTransactionIds.end(),
+ transaction1Id) > 0);
+}
+
} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
index 82aac7e..92411a7 100644
--- a/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
+++ b/services/surfaceflinger/tests/unittests/TransactionTracingTest.cpp
@@ -67,8 +67,14 @@
ASSERT_EQ(actualProto.transactions().size(),
static_cast<int32_t>(expectedTransactions.size()));
for (uint32_t i = 0; i < expectedTransactions.size(); i++) {
- EXPECT_EQ(actualProto.transactions(static_cast<int32_t>(i)).pid(),
- expectedTransactions[i].originPid);
+ const auto expectedTransaction = expectedTransactions[i];
+ const auto protoTransaction = actualProto.transactions(static_cast<int32_t>(i));
+ EXPECT_EQ(protoTransaction.transaction_id(), expectedTransaction.id);
+ EXPECT_EQ(protoTransaction.pid(), expectedTransaction.originPid);
+ for (uint32_t i = 0; i < expectedTransaction.mergedTransactionIds.size(); i++) {
+ EXPECT_EQ(protoTransaction.merged_transaction_ids(static_cast<int32_t>(i)),
+ expectedTransaction.mergedTransactionIds[i]);
+ }
}
}
@@ -92,6 +98,7 @@
TransactionState transaction;
transaction.id = i;
transaction.originPid = static_cast<int32_t>(i);
+ transaction.mergedTransactionIds = std::vector<uint64_t>{i + 100, i + 102};
transactions.emplace_back(transaction);
mTracing.addQueuedTransaction(transaction);
}