Merge "Added SKIP_SCREENSHOT flag for layers"
diff --git a/include/input/Input.h b/include/input/Input.h
index 9feab7b..258adae 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -578,10 +578,18 @@
float getAxisValue(int32_t axis, size_t pointerIndex) const;
+ /**
+ * Get the X coordinate of the latest sample in this MotionEvent for pointer 'pointerIndex'.
+ * Identical to calling getHistoricalX(pointerIndex, getHistorySize()).
+ */
inline float getX(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_X, pointerIndex);
}
+ /**
+ * Get the Y coordinate of the latest sample in this MotionEvent for pointer 'pointerIndex'.
+ * Identical to calling getHistoricalX(pointerIndex, getHistorySize()).
+ */
inline float getY(size_t pointerIndex) const {
return getAxisValue(AMOTION_EVENT_AXIS_Y, pointerIndex);
}
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index ad0a14e..8e00969 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -246,8 +246,6 @@
/* Return a new object that has a duplicate of this channel's fd. */
std::unique_ptr<InputChannel> dup() const;
- void copyTo(InputChannel& outChannel) const;
-
status_t readFromParcel(const android::Parcel* parcel) override;
status_t writeToParcel(android::Parcel* parcel) const override;
@@ -279,8 +277,6 @@
}
private:
- base::unique_fd dupFd() const;
-
std::string mName;
android::base::unique_fd mFd;
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index ee010a3..886f1f7 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -96,7 +96,7 @@
// are included in the movement.
// The positions array contains position information for each pointer in order by
// increasing id. Its size should be equal to the number of one bits in idBits.
- void addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions);
+ void addMovement(nsecs_t eventTime, BitSet32 idBits, const std::vector<Position>& positions);
// Adds movement information for all pointers in a MotionEvent, including historical samples.
void addMovement(const MotionEvent* event);
@@ -149,7 +149,7 @@
virtual void clear() = 0;
virtual void clearPointers(BitSet32 idBits) = 0;
virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) = 0;
+ const std::vector<VelocityTracker::Position>& positions) = 0;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0;
};
@@ -180,8 +180,8 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
+ void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -223,8 +223,8 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
+ void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -257,8 +257,8 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
+ void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -292,8 +292,8 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
- virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions);
+ void addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
diff --git a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
index f44ce0c..a4f4441 100644
--- a/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_interface_utils.h
@@ -93,7 +93,7 @@
//
// Use 'SharedRefBase::make<T>(...)' to make. SharedRefBase has implicit
// ownership. Making this operator private to avoid double-ownership.
-#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30
+#if !defined(__ANDROID_API__) || __ANDROID_API__ >= 30 || defined(__ANDROID_APEX__)
private:
#else
[[deprecated("Prefer SharedRefBase::make<T>(...) if possible.")]]
diff --git a/libs/binder/rust/src/binder.rs b/libs/binder/rust/src/binder.rs
index ceb6ade..81a5f02 100644
--- a/libs/binder/rust/src/binder.rs
+++ b/libs/binder/rust/src/binder.rs
@@ -590,6 +590,15 @@
f.pad(stringify!($interface))
}
}
+
+ // Convert a &dyn $interface to Box<dyn $interface>
+ impl std::borrow::ToOwned for dyn $interface {
+ type Owned = Box<dyn $interface>;
+ fn to_owned(&self) -> Self::Owned {
+ self.as_binder().into_interface()
+ .expect(concat!("Error cloning interface ", stringify!($interface)))
+ }
+ }
};
}
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index ae265ca..a0e9cbf 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -30,6 +30,12 @@
min_sdk_version: "29",
}
+filegroup {
+ name: "libgui_aidl",
+ srcs: ["aidl/**/*.aidl"],
+ path: "aidl/",
+}
+
cc_library_shared {
name: "libgui",
vendor_available: false,
@@ -42,6 +48,7 @@
srcs: [
":framework_native_aidl",
+ ":libgui_aidl",
":libgui_bufferqueue_sources",
"BitTube.cpp",
@@ -74,6 +81,7 @@
"SurfaceControl.cpp",
"SurfaceComposerClient.cpp",
"SyncFeatures.cpp",
+ "TransactionTracing.cpp",
"view/Surface.cpp",
"bufferqueue/1.0/B2HProducerListener.cpp",
"bufferqueue/1.0/H2BGraphicBufferProducer.cpp",
@@ -145,6 +153,7 @@
defaults: ["libgui_bufferqueue-defaults"],
srcs: [
+ ":libgui_aidl",
":libgui_bufferqueue_sources",
],
}
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 5b7d2c5..7a2f656 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -20,6 +20,8 @@
#include <stdint.h>
#include <sys/types.h>
+#include <android/gui/ITransactionTraceListener.h>
+
#include <binder/Parcel.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
@@ -1197,6 +1199,15 @@
return reply.readInt32();
}
+
+ virtual status_t addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) {
+ Parcel data, reply;
+ SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+ SAFE_PARCEL(data.writeStrongBinder, IInterface::asBinder(listener));
+
+ return remote()->transact(BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER, data, &reply);
+ }
};
// Out-of-line virtual method definition to trigger vtable emission in this
@@ -2026,6 +2037,13 @@
reply->writeInt32(result);
return NO_ERROR;
}
+ case ADD_TRANSACTION_TRACE_LISTENER: {
+ CHECK_INTERFACE(ISurfaceComposer, data, reply);
+ sp<gui::ITransactionTraceListener> listener;
+ SAFE_PARCEL(data.readStrongBinder, &listener);
+
+ return addTransactionTraceListener(listener);
+ }
default: {
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/libs/gui/TransactionTracing.cpp b/libs/gui/TransactionTracing.cpp
new file mode 100644
index 0000000..eedc3df
--- /dev/null
+++ b/libs/gui/TransactionTracing.cpp
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "gui/TransactionTracing.h"
+#include "gui/ISurfaceComposer.h"
+
+#include <private/gui/ComposerService.h>
+
+namespace android {
+
+sp<TransactionTraceListener> TransactionTraceListener::sInstance = nullptr;
+std::mutex TransactionTraceListener::sMutex;
+
+TransactionTraceListener::TransactionTraceListener() {}
+
+sp<TransactionTraceListener> TransactionTraceListener::getInstance() {
+ const std::lock_guard<std::mutex> lock(sMutex);
+
+ if (sInstance == nullptr) {
+ sInstance = new TransactionTraceListener;
+
+ sp<ISurfaceComposer> sf(ComposerService::getComposerService());
+ sf->addTransactionTraceListener(sInstance);
+ }
+
+ return sInstance;
+}
+
+binder::Status TransactionTraceListener::onToggled(bool enabled) {
+ ALOGD("TransactionTraceListener: onToggled listener called");
+ mTracingEnabled = enabled;
+
+ return binder::Status::ok();
+}
+
+bool TransactionTraceListener::isTracingEnabled() {
+ return mTracingEnabled;
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/libs/gui/aidl/android/gui/ITransactionTraceListener.aidl b/libs/gui/aidl/android/gui/ITransactionTraceListener.aidl
new file mode 100644
index 0000000..5cd12fd
--- /dev/null
+++ b/libs/gui/aidl/android/gui/ITransactionTraceListener.aidl
@@ -0,0 +1,6 @@
+package android.gui;
+
+/** @hide */
+interface ITransactionTraceListener {
+ void onToggled(boolean enabled);
+}
\ No newline at end of file
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 7c25b97..3627deb 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -22,6 +22,7 @@
#include <binder/IBinder.h>
#include <binder/IInterface.h>
+#include <android/gui/ITransactionTraceListener.h>
#include <gui/IScreenCaptureListener.h>
#include <gui/ITransactionCompletedListener.h>
@@ -486,6 +487,12 @@
*/
virtual status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
int64_t frameTimelineVsyncId) = 0;
+
+ /*
+ * Adds a TransactionTraceListener to listen for transaction tracing state updates.
+ */
+ virtual status_t addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) = 0;
};
// ----------------------------------------------------------------------------
@@ -546,6 +553,7 @@
SET_FRAME_RATE,
ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
SET_FRAME_TIMELINE_VSYNC,
+ ADD_TRANSACTION_TRACE_LISTENER,
// Always append new enum to the end.
};
diff --git a/libs/gui/include/gui/TransactionTracing.h b/libs/gui/include/gui/TransactionTracing.h
new file mode 100644
index 0000000..9efba47
--- /dev/null
+++ b/libs/gui/include/gui/TransactionTracing.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2020 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 <android/gui/BnTransactionTraceListener.h>
+#include <utils/Mutex.h>
+
+namespace android {
+
+class TransactionTraceListener : public gui::BnTransactionTraceListener {
+ static std::mutex sMutex;
+ static sp<TransactionTraceListener> sInstance;
+
+ TransactionTraceListener();
+
+public:
+ static sp<TransactionTraceListener> getInstance();
+
+ binder::Status onToggled(bool enabled) override;
+
+ bool isTracingEnabled();
+
+private:
+ bool mTracingEnabled = false;
+};
+
+} // namespace android
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index ac79583..4d306e7 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -68,10 +68,12 @@
public:
InputSurface(const sp<SurfaceControl> &sc, int width, int height) {
mSurfaceControl = sc;
+ std::unique_ptr<InputChannel> clientChannel;
+ InputChannel::openInputChannelPair("testchannels", mServerChannel, clientChannel);
+ mClientChannel = std::move(clientChannel);
mInputFlinger = getInputFlinger();
- mClientChannel = std::make_shared<InputChannel>();
- mInputFlinger->createInputChannel("testchannels", mClientChannel.get());
+ mInputFlinger->registerInputChannel(*mServerChannel);
populateInputInfo(width, height);
@@ -153,7 +155,7 @@
EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
}
- ~InputSurface() { mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); }
+ ~InputSurface() { mInputFlinger->unregisterInputChannel(mServerChannel->getConnectionToken()); }
void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
const sp<SurfaceControl>&)> transactionBody) {
@@ -190,7 +192,7 @@
}
void populateInputInfo(int width, int height) {
- mInputInfo.token = mClientChannel->getConnectionToken();
+ mInputInfo.token = mServerChannel->getConnectionToken();
mInputInfo.name = "Test info";
mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
mInputInfo.type = InputWindowInfo::Type::BASE_APPLICATION;
@@ -217,6 +219,7 @@
}
public:
sp<SurfaceControl> mSurfaceControl;
+ std::unique_ptr<InputChannel> mServerChannel;
std::shared_ptr<InputChannel> mClientChannel;
sp<IInputFlinger> mInputFlinger;
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 2508ebd..b8b8e4f 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -677,8 +677,7 @@
NewFrameEventsEntry mNewFrameEntryOverride = { 0, 0, 0, nullptr };
};
-
-class FakeSurfaceComposer : public ISurfaceComposer{
+class FakeSurfaceComposer : public ISurfaceComposer {
public:
~FakeSurfaceComposer() override {}
@@ -878,6 +877,11 @@
return NO_ERROR;
}
+ status_t addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& /*listener*/) override {
+ return NO_ERROR;
+ }
+
protected:
IBinder* onAsBinder() override { return nullptr; }
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 85df405..79e15c1 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -377,16 +377,22 @@
}
std::unique_ptr<InputChannel> InputChannel::dup() const {
- base::unique_fd newFd(dupFd());
+ android::base::unique_fd newFd(::dup(getFd()));
+ if (!newFd.ok()) {
+ ALOGE("Could not duplicate fd %i for channel %s: %s", getFd().get(), getName().c_str(),
+ strerror(errno));
+ const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
+ // If this process is out of file descriptors, then throwing that might end up exploding
+ // on the other side of a binder call, which isn't really helpful.
+ // Better to just crash here and hope that the FD leak is slow.
+ // Other failures could be client errors, so we still propagate those back to the caller.
+ LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel %s",
+ getName().c_str());
+ return nullptr;
+ }
return InputChannel::create(getName(), std::move(newFd), getConnectionToken());
}
-void InputChannel::copyTo(InputChannel& outChannel) const {
- outChannel.mName = getName();
- outChannel.mFd = dupFd();
- outChannel.mToken = getConnectionToken();
-}
-
status_t InputChannel::writeToParcel(android::Parcel* parcel) const {
if (parcel == nullptr) {
ALOGE("%s: Null parcel", __func__);
@@ -409,23 +415,6 @@
return mToken;
}
-base::unique_fd InputChannel::dupFd() const {
- android::base::unique_fd newFd(::dup(getFd()));
- if (!newFd.ok()) {
- ALOGE("Could not duplicate fd %i for channel %s: %s", getFd().get(), getName().c_str(),
- strerror(errno));
- const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
- // If this process is out of file descriptors, then throwing that might end up exploding
- // on the other side of a binder call, which isn't really helpful.
- // Better to just crash here and hope that the FD leak is slow.
- // Other failures could be client errors, so we still propagate those back to the caller.
- LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel %s",
- getName().c_str());
- return {};
- }
- return newFd;
-}
-
// --- InputPublisher ---
InputPublisher::InputPublisher(const std::shared_ptr<InputChannel>& channel) : mChannel(channel) {}
diff --git a/libs/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp
index bcf55b0..2c04d42 100644
--- a/libs/input/VelocityControl.cpp
+++ b/libs/input/VelocityControl.cpp
@@ -66,7 +66,7 @@
if (deltaY) {
mRawPosition.y += *deltaY;
}
- mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), &mRawPosition);
+ mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), {mRawPosition});
float vx, vy;
float scale = mParameters.scale;
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 7c28ac5..a44f0b7 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -193,7 +193,11 @@
mStrategy->clearPointers(idBits);
}
-void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits, const Position* positions) {
+void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
+ LOG_ALWAYS_FATAL_IF(idBits.count() != positions.size(),
+ "Mismatching number of pointers, idBits=%" PRIu32 ", positions=%zu",
+ idBits.count(), positions.size());
while (idBits.count() > MAX_POINTERS) {
idBits.clearLastMarkedBit();
}
@@ -285,12 +289,12 @@
pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i));
}
- nsecs_t eventTime;
- Position positions[pointerCount];
+ std::vector<Position> positions;
+ positions.resize(pointerCount);
size_t historySize = event->getHistorySize();
- for (size_t h = 0; h < historySize; h++) {
- eventTime = event->getHistoricalEventTime(h);
+ for (size_t h = 0; h <= historySize; h++) {
+ nsecs_t eventTime = event->getHistoricalEventTime(h);
for (size_t i = 0; i < pointerCount; i++) {
uint32_t index = pointerIndex[i];
positions[index].x = event->getHistoricalX(i, h);
@@ -298,14 +302,6 @@
}
addMovement(eventTime, idBits, positions);
}
-
- eventTime = event->getEventTime();
- for (size_t i = 0; i < pointerCount; i++) {
- uint32_t index = pointerIndex[i];
- positions[index].x = event->getX(i);
- positions[index].y = event->getY(i);
- }
- addMovement(eventTime, idBits, positions);
}
bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
@@ -346,8 +342,9 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
+void LeastSquaresVelocityTrackerStrategy::addMovement(
+ nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
if (mMovements[mIndex].eventTime != eventTime) {
// When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
// of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
@@ -419,13 +416,15 @@
* http://en.wikipedia.org/wiki/Numerical_methods_for_linear_least_squares
* http://en.wikipedia.org/wiki/Gram-Schmidt
*/
-static bool solveLeastSquares(const float* x, const float* y,
- const float* w, uint32_t m, uint32_t n, float* outB, float* outDet) {
+static bool solveLeastSquares(const std::vector<float>& x, const std::vector<float>& y,
+ const std::vector<float>& w, uint32_t n, float* outB, float* outDet) {
+ const size_t m = x.size();
#if DEBUG_STRATEGY
ALOGD("solveLeastSquares: m=%d, n=%d, x=%s, y=%s, w=%s", int(m), int(n),
vectorToString(x, m).c_str(), vectorToString(y, m).c_str(),
vectorToString(w, m).c_str());
#endif
+ LOG_ALWAYS_FATAL_IF(m != y.size() || m != w.size(), "Mismatched vector sizes");
// Expand the X vector to a matrix A, pre-multiplied by the weights.
float a[n][m]; // column-major order
@@ -542,7 +541,9 @@
* the default implementation
*/
static std::optional<std::array<float, 3>> solveUnweightedLeastSquaresDeg2(
- const float* x, const float* y, size_t count) {
+ const std::vector<float>& x, const std::vector<float>& y) {
+ const size_t count = x.size();
+ LOG_ALWAYS_FATAL_IF(count != y.size(), "Mismatching array sizes");
// Solving y = a*x^2 + b*x + c
float sxi = 0, sxiyi = 0, syi = 0, sxi2 = 0, sxi3 = 0, sxi2yi = 0, sxi4 = 0;
@@ -594,11 +595,11 @@
outEstimator->clear();
// Iterate over movement samples in reverse time order and collect samples.
- float x[HISTORY_SIZE];
- float y[HISTORY_SIZE];
- float w[HISTORY_SIZE];
- float time[HISTORY_SIZE];
- uint32_t m = 0;
+ std::vector<float> x;
+ std::vector<float> y;
+ std::vector<float> w;
+ std::vector<float> time;
+
uint32_t index = mIndex;
const Movement& newestMovement = mMovements[mIndex];
do {
@@ -613,13 +614,14 @@
}
const VelocityTracker::Position& position = movement.getPosition(id);
- x[m] = position.x;
- y[m] = position.y;
- w[m] = chooseWeight(index);
- time[m] = -age * 0.000000001f;
+ x.push_back(position.x);
+ y.push_back(position.y);
+ w.push_back(chooseWeight(index));
+ time.push_back(-age * 0.000000001f);
index = (index == 0 ? HISTORY_SIZE : index) - 1;
- } while (++m < HISTORY_SIZE);
+ } while (x.size() < HISTORY_SIZE);
+ const size_t m = x.size();
if (m == 0) {
return false; // no data
}
@@ -632,8 +634,8 @@
if (degree == 2 && mWeighting == WEIGHTING_NONE) {
// Optimize unweighted, quadratic polynomial fit
- std::optional<std::array<float, 3>> xCoeff = solveUnweightedLeastSquaresDeg2(time, x, m);
- std::optional<std::array<float, 3>> yCoeff = solveUnweightedLeastSquaresDeg2(time, y, m);
+ std::optional<std::array<float, 3>> xCoeff = solveUnweightedLeastSquaresDeg2(time, x);
+ std::optional<std::array<float, 3>> yCoeff = solveUnweightedLeastSquaresDeg2(time, y);
if (xCoeff && yCoeff) {
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = 2;
@@ -648,8 +650,8 @@
// General case for an Nth degree polynomial fit
float xdet, ydet;
uint32_t n = degree + 1;
- if (solveLeastSquares(time, x, w, m, n, outEstimator->xCoeff, &xdet)
- && solveLeastSquares(time, y, w, m, n, outEstimator->yCoeff, &ydet)) {
+ if (solveLeastSquares(time, x, w, n, outEstimator->xCoeff, &xdet) &&
+ solveLeastSquares(time, y, w, n, outEstimator->yCoeff, &ydet)) {
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = degree;
outEstimator->confidence = xdet * ydet;
@@ -758,8 +760,9 @@
mPointerIdBits.value &= ~idBits.value;
}
-void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
+void IntegratingVelocityTrackerStrategy::addMovement(
+ nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
uint32_t index = 0;
for (BitSet32 iterIdBits(idBits); !iterIdBits.isEmpty();) {
uint32_t id = iterIdBits.clearFirstMarkedBit();
@@ -876,8 +879,9 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
+void LegacyVelocityTrackerStrategy::addMovement(
+ nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
if (++mIndex == HISTORY_SIZE) {
mIndex = 0;
}
@@ -990,8 +994,9 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const VelocityTracker::Position* positions) {
+void ImpulseVelocityTrackerStrategy::addMovement(
+ nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
if (mMovements[mIndex].eventTime != eventTime) {
// When ACTION_POINTER_DOWN happens, we will first receive ACTION_MOVE with the coordinates
// of the existing pointers, and then ACTION_POINTER_DOWN with the coordinates that include
diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl
index 1771d19..0cdf0bb 100644
--- a/libs/input/android/os/IInputFlinger.aidl
+++ b/libs/input/android/os/IInputFlinger.aidl
@@ -30,8 +30,8 @@
// shouldn't be a concern.
oneway void setInputWindows(in InputWindowInfo[] inputHandles,
in @nullable ISetInputWindowsListener setInputWindowsListener);
- InputChannel createInputChannel(in @utf8InCpp String name);
- void removeInputChannel(in IBinder connectionToken);
+ void registerInputChannel(in InputChannel channel);
+ void unregisterInputChannel(in IBinder connectionToken);
/**
* Sets focus to the window identified by the token. This must be called
* after updating any input window handles.
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 70e997d..5438082 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -389,7 +389,17 @@
return BAD_VALUE;
}
auto canvas = surface->getCanvas();
+ canvas->save();
+ // Before doing any drawing, let's make sure that we'll start at the origin of the display.
+ // Some displays don't start at 0,0 for example when we're mirroring the screen. Also, virtual
+ // displays might have different scaling when compared to the physical screen.
+ canvas->translate(display.physicalDisplay.left, display.physicalDisplay.top);
+ const auto scaleX = static_cast<SkScalar>(display.physicalDisplay.width()) /
+ static_cast<SkScalar>(display.clip.width());
+ const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
+ static_cast<SkScalar>(display.clip.height());
+ canvas->scale(scaleX, scaleY);
canvas->clipRect(SkRect::MakeLTRB(display.clip.left, display.clip.top, display.clip.right,
display.clip.bottom));
canvas->drawColor(0, SkBlendMode::kSrc);
@@ -428,16 +438,22 @@
paint.setColor(SkColor4f{.fR = color.r, .fG = color.g, .fB = color.b, layer->alpha});
}
+ // Layers have a local transform matrix that should be applied to them.
+ canvas->save();
+ canvas->concat(getSkM44(layer->geometry.positionTransform));
+
if (layer->geometry.roundedCornersRadius > 0) {
canvas->drawRRect(getRoundedRect(layer), paint);
} else {
canvas->drawRect(dest, paint);
}
+ canvas->restore();
}
{
ATRACE_NAME("flush surface");
surface->flush();
}
+ canvas->restore();
if (drawFence != nullptr) {
*drawFence = flush();
@@ -471,6 +487,13 @@
return SkRRect::MakeRectXY(rect, cornerRadius, cornerRadius);
}
+inline SkM44 SkiaGLRenderEngine::getSkM44(const mat4& matrix) {
+ return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
+ matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
+ matrix[0][2], matrix[1][2], matrix[2][2], matrix[3][2],
+ matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
+}
+
size_t SkiaGLRenderEngine::getMaxTextureSize() const {
return mGrContext->maxTextureSize();
}
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index b5c4a1e..7103bbd 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -61,6 +61,7 @@
static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config,
int hwcFormat, Protection protection);
inline SkRRect getRoundedRect(const LayerSettings* layer);
+ inline SkM44 getSkM44(const mat4& matrix);
base::unique_fd flush();
bool waitFence(base::unique_fd fenceFd);
diff --git a/libs/ui/include/ui/Transform.h b/libs/ui/include/ui/Transform.h
index 9a434e5..a197b3b 100644
--- a/libs/ui/include/ui/Transform.h
+++ b/libs/ui/include/ui/Transform.h
@@ -111,7 +111,7 @@
void dump(std::string& result, const char* name, const char* prefix = "") const;
void dump(const char* name, const char* prefix = "") const;
- static RotationFlags toRotationFlags(Rotation);
+ static constexpr RotationFlags toRotationFlags(Rotation);
private:
struct mat33 {
@@ -136,7 +136,7 @@
*os << out;
}
-inline Transform::RotationFlags Transform::toRotationFlags(Rotation rotation) {
+inline constexpr Transform::RotationFlags Transform::toRotationFlags(Rotation rotation) {
switch (rotation) {
case ROTATION_0:
return ROT_0;
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 1bcaab4..9a9bca1 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -44,11 +44,11 @@
defaults: ["libgpuservice_defaults"],
cflags: [
"-fvisibility=hidden",
- "-fwhole-program-vtables", // requires ThinLTO
],
lto: {
thin: true,
},
+ whole_program_vtables: true, // Requires ThinLTO
}
filegroup {
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 3d99589..8af9bcb 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -31,25 +31,6 @@
namespace android {
-static int32_t exceptionCodeFromStatusT(status_t status) {
- switch (status) {
- case OK:
- return binder::Status::EX_NONE;
- case INVALID_OPERATION:
- return binder::Status::EX_UNSUPPORTED_OPERATION;
- case BAD_VALUE:
- case BAD_TYPE:
- case NAME_NOT_FOUND:
- return binder::Status::EX_ILLEGAL_ARGUMENT;
- case NO_INIT:
- return binder::Status::EX_ILLEGAL_STATE;
- case PERMISSION_DENIED:
- return binder::Status::EX_SECURITY;
- default:
- return binder::Status::EX_TRANSACTION_FAILED;
- }
-}
-
InputManager::InputManager(
const sp<InputReaderPolicyInterface>& readerPolicy,
const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
@@ -138,7 +119,7 @@
}
// Used by tests only.
-binder::Status InputManager::createInputChannel(const std::string& name, InputChannel* outChannel) {
+binder::Status InputManager::registerInputChannel(const InputChannel& channel) {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
if (uid != AID_SHELL && uid != AID_ROOT) {
@@ -147,17 +128,12 @@
return binder::Status::ok();
}
- base::Result<std::unique_ptr<InputChannel>> channel = mDispatcher->createInputChannel(name);
- if (!channel) {
- return binder::Status::fromExceptionCode(exceptionCodeFromStatusT(channel.error().code()),
- channel.error().message().c_str());
- }
- (*channel)->copyTo(*outChannel);
+ mDispatcher->registerInputChannel(channel.dup());
return binder::Status::ok();
}
-binder::Status InputManager::removeInputChannel(const sp<IBinder>& connectionToken) {
- mDispatcher->removeInputChannel(connectionToken);
+binder::Status InputManager::unregisterInputChannel(const sp<IBinder>& connectionToken) {
+ mDispatcher->unregisterInputChannel(connectionToken);
return binder::Status::ok();
}
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 49bea13..35d2d58 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -108,8 +108,8 @@
const std::vector<InputWindowInfo>& handles,
const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
- binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
- binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
+ binder::Status registerInputChannel(const InputChannel& channel) override;
+ binder::Status unregisterInputChannel(const sp<IBinder>& connectionToken) override;
binder::Status setFocusedWindow(const FocusRequest&) override;
private:
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 46bc055..b645d69 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -129,14 +129,17 @@
protected:
explicit FakeInputReceiver(const sp<InputDispatcher>& dispatcher, const std::string name)
: mDispatcher(dispatcher) {
- mClientChannel = *mDispatcher->createInputChannel(name);
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
+ InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
+ mServerChannel = std::move(serverChannel);
+ mClientChannel = std::move(clientChannel);
mConsumer = std::make_unique<InputConsumer>(mClientChannel);
}
virtual ~FakeInputReceiver() {}
sp<InputDispatcher> mDispatcher;
- std::shared_ptr<InputChannel> mClientChannel;
+ std::shared_ptr<InputChannel> mServerChannel, mClientChannel;
std::unique_ptr<InputConsumer> mConsumer;
PreallocatedInputEventFactory mEventFactory;
};
@@ -149,12 +152,14 @@
FakeWindowHandle(const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
const sp<InputDispatcher>& dispatcher, const std::string name)
: FakeInputReceiver(dispatcher, name), mFrame(Rect(0, 0, WIDTH, HEIGHT)) {
+ mDispatcher->registerInputChannel(mServerChannel);
+
inputApplicationHandle->updateInfo();
mInfo.applicationInfo = *inputApplicationHandle->getInfo();
}
virtual bool updateInfo() override {
- mInfo.token = mClientChannel->getConnectionToken();
+ mInfo.token = mServerChannel->getConnectionToken();
mInfo.name = "FakeWindowHandle";
mInfo.type = InputWindowInfo::Type::APPLICATION;
mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 8b8105d..a10da66 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -28,8 +28,8 @@
// Log debug messages about the dispatch cycle.
#define DEBUG_DISPATCH_CYCLE 0
-// Log debug messages about channel creation
-#define DEBUG_CHANNEL_CREATION 0
+// Log debug messages about registrations.
+#define DEBUG_REGISTRATION 0
// Log debug messages about input event injection.
#define DEBUG_INJECTION 0
@@ -351,16 +351,6 @@
}
}
-static status_t openInputChannelPair(const std::string& name,
- std::shared_ptr<InputChannel>& serverChannel,
- std::unique_ptr<InputChannel>& clientChannel) {
- std::unique_ptr<InputChannel> uniqueServerChannel;
- status_t result = InputChannel::openInputChannelPair(name, uniqueServerChannel, clientChannel);
-
- serverChannel = std::move(uniqueServerChannel);
- return result;
-}
-
const char* InputDispatcher::typeToString(InputDispatcher::FocusResult result) {
switch (result) {
case InputDispatcher::FocusResult::OK:
@@ -422,7 +412,7 @@
while (!mConnectionsByFd.empty()) {
sp<Connection> connection = mConnectionsByFd.begin()->second;
- removeInputChannel(connection->inputChannel->getConnectionToken());
+ unregisterInputChannel(connection->inputChannel->getConnectionToken());
}
}
@@ -4413,72 +4403,67 @@
}
}
-base::Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(
- const std::string& name) {
-#if DEBUG_CHANNEL_CREATION
- ALOGD("channel '%s' ~ createInputChannel", name.c_str());
+status_t InputDispatcher::registerInputChannel(const std::shared_ptr<InputChannel>& inputChannel) {
+#if DEBUG_REGISTRATION
+ ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
#endif
- std::shared_ptr<InputChannel> serverChannel;
- std::unique_ptr<InputChannel> clientChannel;
- status_t result = openInputChannelPair(name, serverChannel, clientChannel);
-
- if (result) {
- return base::Error(result) << "Failed to open input channel pair with name " << name;
- }
-
{ // acquire lock
std::scoped_lock _l(mLock);
- sp<Connection> connection = new Connection(serverChannel, false /*monitor*/, mIdGenerator);
+ sp<Connection> existingConnection = getConnectionLocked(inputChannel->getConnectionToken());
+ if (existingConnection != nullptr) {
+ ALOGW("Attempted to register already registered input channel '%s'",
+ inputChannel->getName().c_str());
+ return BAD_VALUE;
+ }
- int fd = serverChannel->getFd();
+ sp<Connection> connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator);
+
+ int fd = inputChannel->getFd();
mConnectionsByFd[fd] = connection;
- mInputChannelsByToken[serverChannel->getConnectionToken()] = serverChannel;
+ mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
} // release lock
// Wake the looper because some connections have changed.
mLooper->wake();
- return clientChannel;
+ return OK;
}
-base::Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(
- int32_t displayId, bool isGestureMonitor, const std::string& name) {
- std::shared_ptr<InputChannel> serverChannel;
- std::unique_ptr<InputChannel> clientChannel;
- status_t result = openInputChannelPair(name, serverChannel, clientChannel);
- if (result) {
- return base::Error(result) << "Failed to open input channel pair with name " << name;
- }
-
+status_t InputDispatcher::registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
+ int32_t displayId, bool isGestureMonitor) {
{ // acquire lock
std::scoped_lock _l(mLock);
if (displayId < 0) {
- return base::Error(BAD_VALUE) << "Attempted to create input monitor with name " << name
- << " without a specified display.";
+ ALOGW("Attempted to register input monitor without a specified display.");
+ return BAD_VALUE;
}
- sp<Connection> connection = new Connection(serverChannel, true /*monitor*/, mIdGenerator);
+ if (inputChannel->getConnectionToken() == nullptr) {
+ ALOGW("Attempted to register input monitor without an identifying token.");
+ return BAD_VALUE;
+ }
- const int fd = serverChannel->getFd();
+ sp<Connection> connection = new Connection(inputChannel, true /*monitor*/, mIdGenerator);
+
+ const int fd = inputChannel->getFd();
mConnectionsByFd[fd] = connection;
- mInputChannelsByToken[serverChannel->getConnectionToken()] = serverChannel;
+ mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
auto& monitorsByDisplay =
isGestureMonitor ? mGestureMonitorsByDisplay : mGlobalMonitorsByDisplay;
- monitorsByDisplay[displayId].emplace_back(serverChannel);
+ monitorsByDisplay[displayId].emplace_back(inputChannel);
mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
}
-
// Wake the looper because some connections have changed.
mLooper->wake();
- return clientChannel;
+ return OK;
}
-status_t InputDispatcher::removeInputChannel(const sp<IBinder>& connectionToken) {
+status_t InputDispatcher::unregisterInputChannel(const sp<IBinder>& connectionToken) {
{ // acquire lock
std::scoped_lock _l(mLock);
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index c021f65..f3b3dda 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -116,12 +116,12 @@
virtual bool transferTouchFocus(const sp<IBinder>& fromToken,
const sp<IBinder>& toToken) override;
- virtual base::Result<std::unique_ptr<InputChannel>> createInputChannel(
- const std::string& name) override;
+ virtual status_t registerInputChannel(
+ const std::shared_ptr<InputChannel>& inputChannel) override;
virtual void setFocusedWindow(const FocusRequest&) override;
- virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(
- int32_t displayId, bool isGestureMonitor, const std::string& name) override;
- virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) override;
+ virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
+ int32_t displayId, bool isGestureMonitor) override;
+ virtual status_t unregisterInputChannel(const sp<IBinder>& connectionToken) override;
virtual status_t pilferPointers(const sp<IBinder>& token) override;
std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 67d9a06..c3d50ea 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -18,7 +18,6 @@
#define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
#include <InputListener.h>
-#include <android-base/result.h>
#include <android/FocusRequest.h>
#include <android/os/ISetInputWindowsListener.h>
#include <input/InputApplication.h>
@@ -156,16 +155,13 @@
*/
virtual void setFocusedWindow(const FocusRequest&) = 0;
- /**
- * Creates an input channel that may be used as targets for input events.
+ /* Registers input channels that may be used as targets for input events.
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual base::Result<std::unique_ptr<InputChannel>> createInputChannel(
- const std::string& name) = 0;
+ virtual status_t registerInputChannel(const std::shared_ptr<InputChannel>& inputChannel) = 0;
- /**
- * Creates an input channel to be used to monitor input events.
+ /* Registers input channels to be used to monitor input events.
*
* Each monitor must target a specific display and will only receive input events sent to that
* display. If the monitor is a gesture monitor, it will only receive pointer events on the
@@ -173,14 +169,14 @@
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(
- int32_t displayId, bool gestureMonitor, const std::string& name) = 0;
+ virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
+ int32_t displayId, bool gestureMonitor) = 0;
- /* Removes input channels that will no longer receive input events.
+ /* Unregister input channels that will no longer receive input events.
*
* This method may be called on any thread (usually by the input manager).
*/
- virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) = 0;
+ virtual status_t unregisterInputChannel(const sp<IBinder>& connectionToken) = 0;
/* Allows an input monitor steal the current pointer stream away from normal input windows.
*
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 47773d9..577309a 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -48,10 +48,8 @@
const sp<ISetInputWindowsListener>&) {
return binder::Status::ok();
}
- binder::Status createInputChannel(const std::string&, InputChannel*) {
- return binder::Status::ok();
- }
- binder::Status removeInputChannel(const sp<IBinder>&) { return binder::Status::ok(); }
+ binder::Status registerInputChannel(const InputChannel&) { return binder::Status::ok(); }
+ binder::Status unregisterInputChannel(const sp<IBinder>&) { return binder::Status::ok(); }
binder::Status setFocusedWindow(const FocusRequest&) { return binder::Status::ok(); }
private:
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index b00e870..e957826 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -2624,14 +2624,14 @@
// Update the velocity tracker.
{
- VelocityTracker::Position positions[MAX_POINTERS];
- uint32_t count = 0;
- for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) {
+ std::vector<VelocityTracker::Position> positions;
+ for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
const RawPointerData::Pointer& pointer =
mCurrentRawState.rawPointerData.pointerForId(id);
- positions[count].x = pointer.x * mPointerXMovementScale;
- positions[count].y = pointer.y * mPointerYMovementScale;
+ float x = pointer.x * mPointerXMovementScale;
+ float y = pointer.y * mPointerYMovementScale;
+ positions.push_back({x, y});
}
mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits,
positions);
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
index 5c8a8da..b5c5c9e 100644
--- a/services/inputflinger/tests/IInputFlingerQuery.aidl
+++ b/services/inputflinger/tests/IInputFlingerQuery.aidl
@@ -26,5 +26,4 @@
void getInputWindows(out InputWindowInfo[] inputHandles);
void getInputChannels(out InputChannel[] channels);
void getLastFocusRequest(out FocusRequest request);
- void resetInputManager();
}
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 6ef0028..ad6a602 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -548,9 +548,10 @@
class FakeInputReceiver {
public:
- explicit FakeInputReceiver(std::unique_ptr<InputChannel> clientChannel, const std::string name)
+ explicit FakeInputReceiver(const std::shared_ptr<InputChannel>& clientChannel,
+ const std::string name)
: mName(name) {
- mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel));
+ mConsumer = std::make_unique<InputConsumer>(clientChannel);
}
InputEvent* consume() {
@@ -700,10 +701,11 @@
int32_t displayId, std::optional<sp<IBinder>> token = std::nullopt)
: mName(name) {
if (token == std::nullopt) {
- base::Result<std::unique_ptr<InputChannel>> channel =
- dispatcher->createInputChannel(name);
- token = (*channel)->getConnectionToken();
- mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
+ InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
+ mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
+ token = serverChannel->getConnectionToken();
+ dispatcher->registerInputChannel(std::move(serverChannel));
}
inputApplicationHandle->updateInfo();
@@ -1651,9 +1653,10 @@
public:
FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
int32_t displayId, bool isGestureMonitor = false) {
- base::Result<std::unique_ptr<InputChannel>> channel =
- dispatcher->createInputMonitor(displayId, isGestureMonitor, name);
- mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
+ InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
+ mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
+ dispatcher->registerInputMonitor(std::move(serverChannel), displayId, isGestureMonitor);
}
sp<IBinder> getToken() { return mInputReceiver->getToken(); }
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index c368e79..3aef1e4 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -135,6 +135,7 @@
public:
TestInputManager(){};
+ void checkFdFlags(const android::base::unique_fd& fd);
binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles);
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels);
@@ -146,12 +147,10 @@
const std::vector<InputWindowInfo>& handles,
const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
- binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
- binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
+ binder::Status registerInputChannel(const InputChannel& channel) override;
+ binder::Status unregisterInputChannel(const sp<IBinder>& connectionToken) override;
binder::Status setFocusedWindow(const FocusRequest&) override;
- void reset();
-
private:
mutable Mutex mLock;
std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mHandlesPerDisplay;
@@ -165,7 +164,6 @@
binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles) override;
binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
binder::Status getLastFocusRequest(FocusRequest*) override;
- binder::Status resetInputManager() override;
private:
sp<android::TestInputManager> mManager;
@@ -184,11 +182,6 @@
return mManager->getLastFocusRequest(request);
}
-binder::Status TestInputQuery::resetInputManager() {
- mManager->reset();
- return binder::Status::ok();
-}
-
binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
if (mCbFunc != nullptr) {
mCbFunc();
@@ -211,21 +204,23 @@
return binder::Status::ok();
}
-binder::Status TestInputManager::createInputChannel(const std::string& name,
- InputChannel* outChannel) {
+void TestInputManager::checkFdFlags(const android::base::unique_fd& fd) {
+ const int result = fcntl(fd, F_GETFL);
+ EXPECT_NE(result, -1);
+ EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
+}
+
+binder::Status TestInputManager::registerInputChannel(const InputChannel& channel) {
AutoMutex _l(mLock);
- std::unique_ptr<InputChannel> serverChannel;
- std::unique_ptr<InputChannel> clientChannel;
- InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
+ // check Fd flags
+ checkFdFlags(channel.getFd());
- clientChannel->copyTo(*outChannel);
-
- mInputChannels.emplace_back(std::move(serverChannel));
+ mInputChannels.push_back(channel.dup());
return binder::Status::ok();
}
-binder::Status TestInputManager::removeInputChannel(const sp<IBinder>& connectionToken) {
+binder::Status TestInputManager::unregisterInputChannel(const sp<IBinder>& connectionToken) {
AutoMutex _l(mLock);
auto it = std::find_if(mInputChannels.begin(), mInputChannels.end(),
@@ -276,12 +271,6 @@
return binder::Status::ok();
}
-void TestInputManager::reset() {
- mHandlesPerDisplay.clear();
- mInputChannels.clear();
- mFocusRequest = FocusRequest();
-}
-
void InputFlingerServiceTest::SetUp() {
mSetInputWindowsListener = new SetInputWindowsListener([&]() {
std::unique_lock<std::mutex> lock(mLock);
@@ -327,9 +316,7 @@
InitializeInputFlinger();
}
-void InputFlingerServiceTest::TearDown() {
- mQuery->resetInputManager();
-}
+void InputFlingerServiceTest::TearDown() {}
void InputFlingerServiceTest::verifyInputWindowInfo(const InputWindowInfo& info) const {
EXPECT_EQ(mInfo, info);
@@ -380,33 +367,45 @@
}
/**
- * Test InputFlinger service interface createInputChannel
+ * Test InputFlinger service interface registerInputChannel
*/
-TEST_F(InputFlingerServiceTest, CreateInputChannelReturnsUnblockedFd) {
- // Test that the unblocked file descriptor flag is kept across processes over binder
- // transactions.
+TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannel) {
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
- InputChannel channel;
- ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk());
-
- const base::unique_fd& fd = channel.getFd();
- ASSERT_TRUE(fd.ok());
-
- const int result = fcntl(fd, F_GETFL);
- EXPECT_NE(result, -1);
- EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
-}
-
-TEST_F(InputFlingerServiceTest, InputWindow_CreateInputChannel) {
- InputChannel channel;
- ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk());
+ InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
+ mService->registerInputChannel(*serverChannel);
std::vector<::android::InputChannel> channels;
mQuery->getInputChannels(&channels);
ASSERT_EQ(channels.size(), 1UL);
- EXPECT_EQ(channels[0].getConnectionToken(), channel.getConnectionToken());
+ EXPECT_EQ(channels[0], *serverChannel);
- mService->removeInputChannel(channel.getConnectionToken());
+ mService->unregisterInputChannel(serverChannel->getConnectionToken());
+ mQuery->getInputChannels(&channels);
+ EXPECT_EQ(channels.size(), 0UL);
+}
+
+/**
+ * Test InputFlinger service interface registerInputChannel with invalid cases
+ */
+TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannelInvalid) {
+ std::unique_ptr<InputChannel> serverChannel, clientChannel;
+ InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
+
+ std::vector<::android::InputChannel> channels;
+ mQuery->getInputChannels(&channels);
+ EXPECT_EQ(channels.size(), 0UL);
+
+ mService->registerInputChannel(InputChannel());
+ mService->unregisterInputChannel(clientChannel->getConnectionToken());
+
+ mService->registerInputChannel(*serverChannel);
+ mService->registerInputChannel(*clientChannel);
+ mQuery->getInputChannels(&channels);
+ EXPECT_EQ(channels.size(), 2UL);
+
+ mService->unregisterInputChannel(clientChannel->getConnectionToken());
+ mService->unregisterInputChannel(serverChannel->getConnectionToken());
mQuery->getInputChannels(&channels);
EXPECT_EQ(channels.size(), 0UL);
}
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 04e9a2d..7c08e11 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -102,11 +102,11 @@
defaults: ["libsurfaceflinger_defaults"],
cflags: [
"-fvisibility=hidden",
- "-fwhole-program-vtables", // requires ThinLTO
],
lto: {
thin: true,
},
+ whole_program_vtables: true, // Requires ThinLTO
// TODO(b/131771163): Fix broken fuzzer support with LTO.
sanitize: {
fuzzer: false,
diff --git a/services/surfaceflinger/CompositionEngine/Android.bp b/services/surfaceflinger/CompositionEngine/Android.bp
index 4863297..57dc60b 100644
--- a/services/surfaceflinger/CompositionEngine/Android.bp
+++ b/services/surfaceflinger/CompositionEngine/Android.bp
@@ -95,8 +95,9 @@
"tests/MockHWC2.cpp",
"tests/MockHWComposer.cpp",
"tests/MockPowerAdvisor.cpp",
- "tests/OutputTest.cpp",
"tests/OutputLayerTest.cpp",
+ "tests/OutputTest.cpp",
+ "tests/ProjectionSpaceTest.cpp",
"tests/RenderSurfaceTest.cpp",
],
static_libs: [
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index 6552c54..fc1adcc 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -163,9 +163,8 @@
virtual void setCompositionEnabled(bool) = 0;
// Sets the projection state to use
- virtual void setProjection(const ui::Transform&, uint32_t orientation,
- const Rect& orientedDisplaySpaceRect,
- const Rect& layerStackSpaceRect, const Rect& displaySpaceRect) = 0;
+ virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
+ const Rect& orientedDisplaySpaceRect) = 0;
// Sets the bounds to use
virtual void setDisplaySpaceSize(const ui::Size&) = 0;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
index 9d15665..7ca91d8 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/ProjectionSpace.h
@@ -38,14 +38,73 @@
// Rect onto which content is projected.
Rect content;
+
+ // The orientation of this space. This value is meaningful only in relation to the rotation
+ // of another projection space and it's used to determine the rotating transformation when
+ // mapping between the two.
+ // As a convention when using this struct orientation = 0 for the "oriented*" projection
+ // spaces. For example when the display is rotated 90 degress counterclockwise, the orientation
+ // of the display space will become 90, while the orientation of the layer stack space will
+ // remain the same.
+ ui::Rotation orientation = ui::ROTATION_0;
+
+ // Returns a transform which maps this.content into destination.content
+ // and also rotates according to this.orientation and destination.orientation
+ ui::Transform getTransform(const ProjectionSpace& destination) const {
+ ui::Rotation rotation = destination.orientation - orientation;
+
+ // Compute a transformation which rotates the destination in a way it has the same
+ // orientation as us.
+ const uint32_t inverseRotationFlags = ui::Transform::toRotationFlags(-rotation);
+ ui::Transform inverseRotatingTransform;
+ inverseRotatingTransform.set(inverseRotationFlags, destination.bounds.width(),
+ destination.bounds.height());
+ // The destination content rotated so it has the same orientation as us.
+ Rect orientedDestContent = inverseRotatingTransform.transform(destination.content);
+
+ // Compute translation from the source content to (0, 0).
+ const float sourceX = content.left;
+ const float sourceY = content.top;
+ ui::Transform sourceTranslation;
+ sourceTranslation.set(-sourceX, -sourceY);
+
+ // Compute scaling transform which maps source content to destination content, assuming
+ // they are both at (0, 0).
+ ui::Transform scale;
+ const float scaleX = static_cast<float>(orientedDestContent.width()) / content.width();
+ const float scaleY = static_cast<float>(orientedDestContent.height()) / content.height();
+ scale.set(scaleX, 0, 0, scaleY);
+
+ // Compute translation from (0, 0) to the orientated destination content.
+ const float destX = orientedDestContent.left;
+ const float destY = orientedDestContent.top;
+ ui::Transform destTranslation;
+ destTranslation.set(destX, destY);
+
+ // Compute rotation transform.
+ const uint32_t orientationFlags = ui::Transform::toRotationFlags(rotation);
+ auto orientedDestWidth = destination.bounds.width();
+ auto orientedDestHeight = destination.bounds.height();
+ if (rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270) {
+ std::swap(orientedDestWidth, orientedDestHeight);
+ }
+ ui::Transform rotationTransform;
+ rotationTransform.set(orientationFlags, orientedDestWidth, orientedDestHeight);
+
+ // The layerStackSpaceRect and orientedDisplaySpaceRect are both in the logical orientation.
+ // Apply the logical translation, scale to physical size, apply the
+ // physical translation and finally rotate to the physical orientation.
+ return rotationTransform * destTranslation * scale * sourceTranslation;
+ }
};
} // namespace compositionengine
inline std::string to_string(const android::compositionengine::ProjectionSpace& space) {
- return android::base::StringPrintf("ProjectionSpace(bounds = %s, content = %s)",
- to_string(space.bounds).c_str(),
- to_string(space.content).c_str());
+ return android::base::
+ StringPrintf("ProjectionSpace(bounds = %s, content = %s, orientation = %s)",
+ to_string(space.bounds).c_str(), to_string(space.content).c_str(),
+ toCString(space.orientation));
}
// Defining PrintTo helps with Google Tests.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index e009894..6fe93bf 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -38,9 +38,8 @@
bool isValid() const override;
std::optional<DisplayId> getDisplayId() const override;
void setCompositionEnabled(bool) override;
- void setProjection(const ui::Transform&, uint32_t orientation,
- const Rect& orientedDisplaySpaceRect, const Rect& layerStackSpaceRect,
- const Rect& displaySpaceRect) override;
+ void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
+ const Rect& orientedDisplaySpaceRect) override;
void setDisplaySpaceSize(const ui::Size&) override;
void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index 462d952..f4d2b56 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -64,13 +64,11 @@
uint32_t layerStackId{~0u};
// The common space for all layers in the layer stack. layerStackSpace.content is the Rect
- // which gets projected on the display. The content in this space is always in a single
- // orientation.
+ // which gets projected on the display. The orientation of this space is always ROTATION_0.
ProjectionSpace layerStackSpace;
// Oriented physical display space. It will have the same size as displaySpace oriented to
- // match the orientation of layerStackSpace. The content in this space is always in a single
- // orientation.
+ // match the orientation of layerStackSpace. The orientation of this space is always ROTATION_0.
ProjectionSpace orientedDisplaySpace;
// The space of the physical display. It is as big as the currently active display mode. The
@@ -80,9 +78,6 @@
// Transformation from layerStackSpace to displaySpace
ui::Transform transform;
- // The physical orientation of the display, expressed as ui::Transform orientation flags.
- uint32_t orientation{0};
-
// If true, RenderEngine filtering should be enabled
bool needsFiltering{false};
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 5350611..19025c1 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -36,8 +36,7 @@
MOCK_CONST_METHOD0(getDisplayId, std::optional<DisplayId>());
MOCK_METHOD1(setCompositionEnabled, void(bool));
- MOCK_METHOD5(setProjection,
- void(const ui::Transform&, uint32_t, const Rect&, const Rect&, const Rect&));
+ MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
MOCK_METHOD1(setDisplaySpaceSize, void(const ui::Size&));
MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index 816a09b..abb8769 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -105,25 +105,34 @@
dirtyEntireOutput();
}
-void Output::setProjection(const ui::Transform& transform, uint32_t orientation,
- const Rect& orientedDisplaySpaceRect, const Rect& layerStackSpaceRect,
- const Rect& displaySpaceRect) {
+void Output::setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
+ const Rect& orientedDisplaySpaceRect) {
auto& outputState = editState();
- outputState.transform = transform;
- outputState.orientation = orientation;
- outputState.displaySpace.content = displaySpaceRect;
- // outputState.displaySpace.bounds should be already set from setDisplaySpaceSize().
- outputState.orientedDisplaySpace.content = orientedDisplaySpaceRect;
+ outputState.displaySpace.orientation = orientation;
+ // outputState.displaySpace.bounds should be already set from setDisplaySpaceSize().
+
+ // Compute the orientedDisplaySpace bounds
ui::Size orientedSize = outputState.displaySpace.bounds.getSize();
- if (orientation == ui::Transform::ROT_90 || orientation == ui::Transform::ROT_270) {
+ if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
std::swap(orientedSize.width, orientedSize.height);
}
outputState.orientedDisplaySpace.bounds = Rect(orientedSize);
+ outputState.orientedDisplaySpace.content = orientedDisplaySpaceRect;
+
+ // Compute displaySpace.content
+ const uint32_t transformOrientationFlags = ui::Transform::toRotationFlags(orientation);
+ ui::Transform rotation;
+ if (transformOrientationFlags != ui::Transform::ROT_INVALID) {
+ const auto displaySize = outputState.displaySpace.bounds;
+ rotation.set(transformOrientationFlags, displaySize.width(), displaySize.height());
+ }
+ outputState.displaySpace.content = rotation.transform(orientedDisplaySpaceRect);
outputState.layerStackSpace.content = layerStackSpaceRect;
outputState.layerStackSpace.bounds = layerStackSpaceRect;
- outputState.needsFiltering = transform.needsBilinearFiltering();
+ outputState.transform = outputState.layerStackSpace.getTransform(outputState.displaySpace);
+ outputState.needsFiltering = outputState.transform.needsBilinearFiltering();
dirtyEntireOutput();
}
@@ -870,7 +879,8 @@
renderengine::DisplaySettings clientCompositionDisplay;
clientCompositionDisplay.physicalDisplay = outputState.displaySpace.content;
clientCompositionDisplay.clip = outputState.layerStackSpace.content;
- clientCompositionDisplay.orientation = outputState.orientation;
+ clientCompositionDisplay.orientation =
+ ui::Transform::toRotationFlags(outputState.displaySpace.orientation);
clientCompositionDisplay.outputDataspace = mDisplayColorProfile->hasWideColorGamut()
? outputState.dataspace
: ui::Dataspace::UNKNOWN;
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 0f53641..0faab6f 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -133,7 +133,8 @@
* the code below applies the primary display's inverse transform to the
* buffer
*/
- uint32_t invTransformOrient = outputState.orientation;
+ uint32_t invTransformOrient =
+ ui::Transform::toRotationFlags(outputState.displaySpace.orientation);
// calculate the inverse transform
if (invTransformOrient & HAL_TRANSFORM_ROT_90) {
invTransformOrient ^= HAL_TRANSFORM_FLIP_V | HAL_TRANSFORM_FLIP_H;
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index d9fb098..dcfc162 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -21,6 +21,7 @@
#include <compositionengine/mock/LayerFE.h>
#include <compositionengine/mock/Output.h>
#include <gtest/gtest.h>
+#include <log/log.h>
#include "MockHWC2.h"
#include "MockHWComposer.h"
@@ -55,6 +56,22 @@
return expected.r == arg.r && expected.g == arg.g && expected.b == arg.b && expected.a == arg.a;
}
+ui::Rotation toRotation(uint32_t rotationFlag) {
+ switch (rotationFlag) {
+ case ui::Transform::RotationFlags::ROT_0:
+ return ui::ROTATION_0;
+ case ui::Transform::RotationFlags::ROT_90:
+ return ui::ROTATION_90;
+ case ui::Transform::RotationFlags::ROT_180:
+ return ui::ROTATION_180;
+ case ui::Transform::RotationFlags::ROT_270:
+ return ui::ROTATION_270;
+ default:
+ LOG_FATAL("Unexpected rotation flag %d", rotationFlag);
+ return ui::Rotation(-1);
+ }
+}
+
struct OutputLayerTest : public testing::Test {
struct OutputLayer final : public impl::OutputLayer {
OutputLayer(const compositionengine::Output& output, sp<compositionengine::LayerFE> layerFE)
@@ -209,7 +226,7 @@
mLayerFEState.geomBufferUsesDisplayInverseTransform = entry.bufferInvDisplay;
mLayerFEState.geomBufferTransform = entry.buffer;
- mOutputState.orientation = entry.display;
+ mOutputState.displaySpace.orientation = toRotation(entry.display);
EXPECT_THAT(calculateOutputSourceCrop(), entry.expected) << "entry " << i;
}
@@ -358,7 +375,7 @@
mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080);
mLayerFEState.geomBufferTransform = entry.buffer;
- mOutputState.orientation = entry.display;
+ mOutputState.displaySpace.orientation = toRotation(entry.display);
mOutputState.transform = ui::Transform{entry.display};
const auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(entry.display);
@@ -470,7 +487,7 @@
mLayerFEState.geomLayerTransform.set(entry.layer, 1920, 1080);
mLayerFEState.geomBufferTransform = entry.buffer;
- mOutputState.orientation = entry.display;
+ mOutputState.displaySpace.orientation = toRotation(entry.display);
mOutputState.transform = ui::Transform{entry.display};
const auto actual = mOutputLayer.calculateOutputRelativeBufferTransform(entry.internal);
@@ -853,7 +870,7 @@
// This test simulates a scenario where displayInstallOrientation is set to
// ROT_90. This only has an effect on the transform; orientation stays 0 (see
// DisplayDevice::setProjection).
- mOutputState.orientation = TR_IDENT;
+ mOutputState.displaySpace.orientation = ui::ROTATION_0;
mOutputState.transform = ui::Transform{TR_ROT_90};
// Buffers are pre-rotated based on the transform hint (ROT_90); their
// geomBufferTransform is set to the inverse transform.
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index 23efd2d..c01f3e0 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -236,19 +236,15 @@
*/
TEST_F(OutputTest, setProjectionTriviallyWorks) {
- const ui::Transform transform{ui::Transform::ROT_180};
- const int32_t orientation = 123;
+ const ui::Rotation orientation = ui::ROTATION_90;
const Rect frame{1, 2, 3, 4};
const Rect viewport{5, 6, 7, 8};
- const Rect destinationClip{13, 14, 15, 16};
- mOutput->setProjection(transform, orientation, frame, viewport, destinationClip);
+ mOutput->setProjection(orientation, viewport, frame);
- EXPECT_THAT(mOutput->getState().transform, transform);
- EXPECT_EQ(orientation, mOutput->getState().orientation);
+ EXPECT_EQ(orientation, mOutput->getState().displaySpace.orientation);
EXPECT_EQ(frame, mOutput->getState().orientedDisplaySpace.content);
EXPECT_EQ(viewport, mOutput->getState().layerStackSpace.content);
- EXPECT_EQ(destinationClip, mOutput->getState().displaySpace.content);
}
/*
@@ -2783,8 +2779,8 @@
mOutput.mState.orientedDisplaySpace.content = kDefaultOutputFrame;
mOutput.mState.layerStackSpace.content = kDefaultOutputViewport;
mOutput.mState.displaySpace.content = kDefaultOutputDestinationClip;
- mOutput.mState.transform = ui::Transform{kDefaultOutputOrientation};
- mOutput.mState.orientation = kDefaultOutputOrientation;
+ mOutput.mState.transform = ui::Transform{kDefaultOutputOrientationFlags};
+ mOutput.mState.displaySpace.orientation = kDefaultOutputOrientation;
mOutput.mState.dataspace = kDefaultOutputDataspace;
mOutput.mState.colorTransformMatrix = kDefaultColorTransformMat;
mOutput.mState.isSecure = false;
@@ -2819,7 +2815,9 @@
// Call this member function to start using the mini-DSL defined above.
[[nodiscard]] auto verify() { return ExecuteState::make(this); }
- static constexpr uint32_t kDefaultOutputOrientation = TR_IDENT;
+ static constexpr ui::Rotation kDefaultOutputOrientation = ui::ROTATION_0;
+ static constexpr uint32_t kDefaultOutputOrientationFlags =
+ ui::Transform::toRotationFlags(kDefaultOutputOrientation);
static constexpr ui::Dataspace kDefaultOutputDataspace = ui::Dataspace::UNKNOWN;
static constexpr ui::Dataspace kExpensiveOutputDataspace = ui::Dataspace::DISPLAY_P3;
static constexpr float kDefaultMaxLuminance = 0.9f;
@@ -3116,7 +3114,7 @@
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientation})
+ Region::INVALID_REGION, kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3127,7 +3125,7 @@
.andIfSkipColorTransform(false)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientation})
+ Region::INVALID_REGION, kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3139,7 +3137,7 @@
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace,
kDefaultColorTransformMat, Region::INVALID_REGION,
- kDefaultOutputOrientation})
+ kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3151,7 +3149,7 @@
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace,
kDefaultColorTransformMat, Region::INVALID_REGION,
- kDefaultOutputOrientation})
+ kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3163,7 +3161,7 @@
.andIfSkipColorTransform(true)
.thenExpectDisplaySettingsUsed({kDefaultOutputDestinationClip, kDefaultOutputViewport,
kDefaultMaxLuminance, kDefaultOutputDataspace, mat4(),
- Region::INVALID_REGION, kDefaultOutputOrientation})
+ Region::INVALID_REGION, kDefaultOutputOrientationFlags})
.execute()
.expectAFenceWasReturned();
}
@@ -3409,8 +3407,9 @@
mOutput.mState.orientedDisplaySpace.content = kDisplayFrame;
mOutput.mState.layerStackSpace.content = kDisplayViewport;
mOutput.mState.displaySpace.content = kDisplayDestinationClip;
- mOutput.mState.transform = ui::Transform{kDisplayOrientation};
- mOutput.mState.orientation = kDisplayOrientation;
+ mOutput.mState.transform =
+ ui::Transform{ui::Transform::toRotationFlags(kDisplayOrientation)};
+ mOutput.mState.displaySpace.orientation = kDisplayOrientation;
mOutput.mState.needsFiltering = false;
mOutput.mState.isSecure = false;
@@ -3434,7 +3433,7 @@
EXPECT_CALL(mOutput, getOutputLayerCount()).WillRepeatedly(Return(mLayers.size()));
}
- static constexpr uint32_t kDisplayOrientation = TR_IDENT;
+ static constexpr ui::Rotation kDisplayOrientation = ui::ROTATION_0;
static constexpr ui::Dataspace kDisplayDataspace = ui::Dataspace::UNKNOWN;
static const Rect kDisplayFrame;
@@ -3918,14 +3917,14 @@
const Rect kPortraitFrame(0, 0, 1000, 2000);
const Rect kPortraitViewport(0, 0, 2000, 1000);
const Rect kPortraitDestinationClip(0, 0, 1000, 2000);
- const uint32_t kPortraitOrientation = TR_ROT_90;
+ const ui::Rotation kPortraitOrientation = ui::ROTATION_90;
constexpr ui::Dataspace kOutputDataspace = ui::Dataspace::DISPLAY_P3;
mOutput.mState.orientedDisplaySpace.content = kPortraitFrame;
mOutput.mState.layerStackSpace.content = kPortraitViewport;
mOutput.mState.displaySpace.content = kPortraitDestinationClip;
- mOutput.mState.transform = ui::Transform{kPortraitOrientation};
- mOutput.mState.orientation = kPortraitOrientation;
+ mOutput.mState.transform = ui::Transform{ui::Transform::toRotationFlags(kPortraitOrientation)};
+ mOutput.mState.displaySpace.orientation = kPortraitOrientation;
mOutput.mState.needsFiltering = false;
mOutput.mState.isSecure = true;
diff --git a/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp b/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp
new file mode 100644
index 0000000..704f5a8
--- /dev/null
+++ b/services/surfaceflinger/CompositionEngine/tests/ProjectionSpaceTest.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <compositionengine/ProjectionSpace.h>
+#include <gtest/gtest.h>
+
+namespace android::compositionengine {
+namespace {
+
+// Returns a rectangular strip along the side of the given rect pointed by
+// rotation. E.g. if rotation is ROTATION_0, the srip will be along the top
+// side, if it is ROTATION_90 the stip will be along the right wall.
+// One of the dimensions of the strip will be 0 and the other one will match
+// the length of the corresponding side.
+// The strip will be contained inside the given rect.
+Rect getSideStrip(const Rect& rect, ui::Rotation rotation) {
+ int width, height;
+ if (rotation == ui::ROTATION_90 || rotation == ui::ROTATION_270) {
+ width = 0;
+ height = rect.height();
+ } else {
+ width = rect.width();
+ height = 0;
+ }
+
+ if (rotation == ui::ROTATION_0 || rotation == ui::ROTATION_270) {
+ return Rect(rect.left, rect.top, rect.left + width, rect.top + height);
+ }
+
+ if (rotation == ui::ROTATION_90) {
+ return Rect(rect.right, rect.top, rect.right + width, rect.top + height);
+ }
+
+ if (rotation == ui::ROTATION_180) {
+ return Rect(rect.left, rect.bottom, rect.left + width, rect.bottom + height);
+ }
+
+ return Rect::INVALID_RECT;
+}
+} // namespace
+
+TEST(ProjectionSpaceTest, getTransformToSelfIsIdentity) {
+ ProjectionSpace space;
+ space.content = Rect(100, 200);
+ space.bounds = Rect(100, 200);
+
+ const ui::Transform identity;
+ for (int rotation = 0; rotation <= 3; rotation++) {
+ space.orientation = ui::Rotation(rotation);
+ EXPECT_EQ(space.getTransform(space), identity);
+ }
+}
+
+TEST(ProjectionSpaceTest, getTransformWhenTranslationIsNeeded) {
+ ProjectionSpace source;
+ source.content = Rect(10, 10, 20, 20);
+ source.bounds = Rect(100, 200);
+
+ ProjectionSpace dest;
+ dest.content = Rect(10, 20, 30, 20);
+ dest.bounds = source.bounds;
+
+ const auto transform = source.getTransform(dest);
+ EXPECT_EQ(transform.transform(source.content), dest.content);
+}
+
+TEST(ProjectionSpaceTest, getTransformWhenScaleIsNeeded) {
+ ProjectionSpace source;
+ source.content = Rect(0, 0, 20, 20);
+ source.bounds = Rect(100, 200);
+
+ ProjectionSpace dest;
+ dest.content = Rect(0, 0, 40, 30);
+ dest.bounds = source.bounds;
+
+ const auto transform = source.getTransform(dest);
+ EXPECT_EQ(transform.transform(source.content), dest.content);
+}
+
+TEST(ProjectionSpaceTest, getSideStripTest) {
+ const Rect rect(10, 20, 40, 100);
+ EXPECT_EQ(getSideStrip(rect, ui::ROTATION_0), Rect(10, 20, 40, 20));
+ EXPECT_EQ(getSideStrip(rect, ui::ROTATION_90), Rect(40, 20, 40, 100));
+ EXPECT_EQ(getSideStrip(rect, ui::ROTATION_180), Rect(10, 100, 40, 100));
+ EXPECT_EQ(getSideStrip(rect, ui::ROTATION_270), Rect(10, 20, 10, 100));
+}
+
+void testTransform(const ProjectionSpace& source, const ProjectionSpace& dest) {
+ const auto transform = source.getTransform(dest);
+ EXPECT_EQ(transform.transform(source.content), dest.content)
+ << "Source content doesn't map to dest content when projecting " << to_string(source)
+ << " onto " << to_string(dest);
+
+ // We take a strip at the top (according to the orientation) of each
+ // content rect and verify that transform maps between them. This way we
+ // verify that the transform is rotating properly.
+ // In the following example the strip is marked with asterisks:
+ //
+ // ******* +-------*
+ // | | | *
+ // | | | *
+ // +-----+ +-------*
+ // source(ROTATION_0) dest (ROTATION_90)
+ const auto sourceStrip = getSideStrip(source.content, source.orientation);
+ const auto destStrip = getSideStrip(dest.content, dest.orientation);
+ ASSERT_NE(sourceStrip, Rect::INVALID_RECT);
+ ASSERT_NE(destStrip, Rect::INVALID_RECT);
+ const auto mappedStrip = transform.transform(sourceStrip);
+ EXPECT_EQ(mappedStrip, destStrip)
+ << to_string(sourceStrip) << " maps to " << to_string(mappedStrip) << " instead of "
+ << to_string(destStrip) << " when projecting " << to_string(source) << " onto "
+ << to_string(dest);
+}
+
+TEST(ProjectionSpaceTest, getTransformWithOrienations) {
+ ProjectionSpace source;
+ source.bounds = Rect(12, 13, 678, 789);
+ source.content = Rect(40, 50, 234, 343);
+ ProjectionSpace dest;
+ dest.bounds = Rect(17, 18, 879, 564);
+ dest.content = Rect(43, 52, 432, 213);
+
+ for (int sourceRot = 0; sourceRot <= 3; sourceRot++) {
+ source.orientation = ui::Rotation(sourceRot);
+ for (int destRot = 0; destRot <= 3; destRot++) {
+ dest.orientation = ui::Rotation(destRot);
+ testTransform(source, dest);
+ }
+ }
+}
+
+} // namespace android::compositionengine
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index b53f88d..7df9b76 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -163,6 +163,10 @@
Rect orientedDisplaySpaceRect) {
mOrientation = orientation;
+ if (isPrimary()) {
+ sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
+ }
+
const Rect& displayBounds = getCompositionDisplay()->getState().displaySpace.bounds;
const int displayWidth = displayBounds.width();
const int displayHeight = displayBounds.height();
@@ -184,52 +188,11 @@
}
}
- ui::Transform logicalTranslation, physicalTranslation, scale;
- const float sourceWidth = layerStackSpaceRect.width();
- const float sourceHeight = layerStackSpaceRect.height();
- const float destWidth = orientedDisplaySpaceRect.width();
- const float destHeight = orientedDisplaySpaceRect.height();
- if (sourceWidth != destWidth || sourceHeight != destHeight) {
- const float scaleX = destWidth / sourceWidth;
- const float scaleY = destHeight / sourceHeight;
- scale.set(scaleX, 0, 0, scaleY);
- }
-
- const float sourceX = layerStackSpaceRect.left;
- const float sourceY = layerStackSpaceRect.top;
- const float destX = orientedDisplaySpaceRect.left;
- const float destY = orientedDisplaySpaceRect.top;
- logicalTranslation.set(-sourceX, -sourceY);
- physicalTranslation.set(destX, destY);
-
// 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;
- const uint32_t transformOrientationFlags = ui::Transform::toRotationFlags(transformOrientation);
- ui::Transform rotation;
- if (transformOrientationFlags != ui::Transform::ROT_INVALID) {
- rotation.set(transformOrientationFlags, displayWidth, displayHeight);
- }
-
- // The layerStackSpaceRect and orientedDisplaySpaceRect are both in the logical orientation.
- // Apply the logical translation, scale to physical size, apply the
- // physical translation and finally rotate to the physical orientation.
- ui::Transform globalTransform = rotation * physicalTranslation * scale * logicalTranslation;
-
- Rect displaySpaceRect = globalTransform.transform(layerStackSpaceRect);
- if (displaySpaceRect.isEmpty()) {
- displaySpaceRect = displayBounds;
- }
- // Make sure the displaySpaceRect is contained in the display bounds
- displaySpaceRect.intersect(displayBounds, &displaySpaceRect);
-
- if (isPrimary()) {
- sPrimaryDisplayRotationFlags = ui::Transform::toRotationFlags(orientation);
- }
-
- getCompositionDisplay()->setProjection(globalTransform, transformOrientationFlags,
- orientedDisplaySpaceRect, layerStackSpaceRect,
- displaySpaceRect);
+ getCompositionDisplay()->setProjection(transformOrientation, layerStackSpaceRect,
+ orientedDisplaySpaceRect);
}
ui::Transform::RotationFlags DisplayDevice::getPrimaryDisplayRotationFlags() {
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 05aa22c..6a0f24a 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -4870,6 +4870,7 @@
}
return OK;
}
+ case ADD_TRANSACTION_TRACE_LISTENER:
case CAPTURE_DISPLAY_BY_ID: {
IPCThreadState* ipc = IPCThreadState::self();
const int uid = ipc->getCallingUid();
@@ -6215,6 +6216,17 @@
}));
}
+status_t SurfaceFlinger::addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) {
+ if (!listener) {
+ return BAD_VALUE;
+ }
+
+ mInterceptor->addTransactionTraceListener(listener);
+
+ return NO_ERROR;
+}
+
} // namespace android
#if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 94e8d9b..3b4d5d4 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -596,6 +596,9 @@
status_t setFrameTimelineVsync(const sp<IGraphicBufferProducer>& surface,
int64_t frameTimelineVsyncId) override;
+ status_t addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) override;
+
// Implements IBinder::DeathRecipient.
void binderDied(const wp<IBinder>& who) override;
@@ -1112,7 +1115,7 @@
volatile nsecs_t mDebugInTransaction = 0;
bool mForceFullDamage = false;
bool mPropagateBackpressureClientComposition = false;
- std::unique_ptr<SurfaceInterceptor> mInterceptor;
+ sp<SurfaceInterceptor> mInterceptor;
SurfaceTracing mTracing{*this};
std::mutex mTracingLock;
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
index fb08e69..93d36a6 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.cpp
@@ -68,9 +68,8 @@
return std::make_unique<Scheduler>(configs, callback);
}
-std::unique_ptr<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(
- SurfaceFlinger* flinger) {
- return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+sp<SurfaceInterceptor> DefaultFactory::createSurfaceInterceptor(SurfaceFlinger* flinger) {
+ return new android::impl::SurfaceInterceptor(flinger);
}
sp<StartPropertySetThread> DefaultFactory::createStartPropertySetThread(
diff --git a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
index 86e5a7a..e06c2f4 100644
--- a/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerDefaultFactory.h
@@ -32,7 +32,7 @@
const scheduler::RefreshRateConfigs&) override;
std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
ISchedulerCallback&) override;
- std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override;
+ sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) override;
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override;
sp<DisplayDevice> createDisplayDevice(DisplayDeviceCreationArgs&) override;
sp<GraphicBuffer> createGraphicBuffer(uint32_t width, uint32_t height, PixelFormat format,
diff --git a/services/surfaceflinger/SurfaceFlingerFactory.h b/services/surfaceflinger/SurfaceFlingerFactory.h
index 753476e..41ccc10 100644
--- a/services/surfaceflinger/SurfaceFlingerFactory.h
+++ b/services/surfaceflinger/SurfaceFlingerFactory.h
@@ -73,7 +73,7 @@
const scheduler::RefreshRateConfigs&) = 0;
virtual std::unique_ptr<Scheduler> createScheduler(const scheduler::RefreshRateConfigs&,
ISchedulerCallback&) = 0;
- virtual std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
+ virtual sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger*) = 0;
virtual sp<StartPropertySetThread> createStartPropertySetThread(
bool timestampPropertyValue) = 0;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index c15d0df..9d705e5 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -45,6 +45,24 @@
{
}
+void SurfaceInterceptor::addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) {
+ sp<IBinder> asBinder = IInterface::asBinder(listener);
+
+ std::scoped_lock lock(mListenersMutex);
+
+ asBinder->linkToDeath(this);
+
+ listener->onToggled(mEnabled); // notifies of current state
+
+ mTraceToggledListeners.emplace(asBinder, listener);
+}
+
+void SurfaceInterceptor::binderDied(const wp<IBinder>& who) {
+ std::scoped_lock lock(mListenersMutex);
+ mTraceToggledListeners.erase(who);
+}
+
void SurfaceInterceptor::enable(const SortedVector<sp<Layer>>& layers,
const DefaultKeyedVector< wp<IBinder>, DisplayDeviceState>& displays)
{
@@ -52,8 +70,14 @@
return;
}
ATRACE_CALL();
+ {
+ std::scoped_lock lock(mListenersMutex);
+ for (const auto& [_, listener] : mTraceToggledListeners) {
+ listener->onToggled(true);
+ }
+ }
mEnabled = true;
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ std::scoped_lock<std::mutex> protoGuard(mTraceMutex);
saveExistingDisplaysLocked(displays);
saveExistingSurfacesLocked(layers);
}
@@ -63,8 +87,14 @@
return;
}
ATRACE_CALL();
- std::lock_guard<std::mutex> protoGuard(mTraceMutex);
+ {
+ std::scoped_lock lock(mListenersMutex);
+ for (const auto& [_, listener] : mTraceToggledListeners) {
+ listener->onToggled(false);
+ }
+ }
mEnabled = false;
+ std::scoped_lock<std::mutex> protoGuard(mTraceMutex);
status_t err(writeProtoFileLocked());
ALOGE_IF(err == PERMISSION_DENIED, "Could not save the proto file! Permission denied");
ALOGE_IF(err == NOT_ENOUGH_DATA, "Could not save the proto file! There are missing fields");
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 1798b5a..4908bae 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -21,6 +21,8 @@
#include <mutex>
+#include <binder/IBinder.h>
+
#include <gui/LayerState.h>
#include <utils/KeyedVector.h>
@@ -48,7 +50,7 @@
constexpr auto DEFAULT_FILENAME = "/data/misc/wmtrace/transaction_trace.pb";
-class SurfaceInterceptor {
+class SurfaceInterceptor : public IBinder::DeathRecipient {
public:
virtual ~SurfaceInterceptor();
@@ -58,6 +60,10 @@
virtual void disable() = 0;
virtual bool isEnabled() = 0;
+ virtual void addTransactionTraceListener(
+ const sp<gui::ITransactionTraceListener>& listener) = 0;
+ virtual void binderDied(const wp<IBinder>& who) = 0;
+
// Intercept display and surface transactions
virtual void saveTransaction(
const Vector<ComposerState>& stateUpdates,
@@ -95,6 +101,9 @@
void disable() override;
bool isEnabled() override;
+ void addTransactionTraceListener(const sp<gui::ITransactionTraceListener>& listener) override;
+ void binderDied(const wp<IBinder>& who) override;
+
// Intercept display and surface transactions
void saveTransaction(const Vector<ComposerState>& stateUpdates,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>& displays,
@@ -193,6 +202,9 @@
std::mutex mTraceMutex {};
Trace mTrace {};
SurfaceFlinger* const mFlinger;
+ std::mutex mListenersMutex;
+ std::map<wp<IBinder>, sp<gui::ITransactionTraceListener>> mTraceToggledListeners
+ GUARDED_BY(mListenersMutex);
};
} // namespace impl
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 4e98af1..b750d6b 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -155,7 +155,7 @@
renderengine::mock::RenderEngine* mRenderEngine = new renderengine::mock::RenderEngine();
Hwc2::mock::Composer* mComposer = nullptr;
mock::MessageQueue* mMessageQueue = new mock::MessageQueue();
- mock::SurfaceInterceptor* mSurfaceInterceptor = new mock::SurfaceInterceptor();
+ sp<mock::SurfaceInterceptor> mSurfaceInterceptor = new mock::SurfaceInterceptor;
mock::VsyncController* mVsyncController = new mock::VsyncController;
mock::VSyncTracker* mVSyncTracker = new mock::VSyncTracker;
@@ -194,7 +194,7 @@
injectMockScheduler();
mFlinger.mutableEventQueue().reset(mMessageQueue);
mFlinger.setupRenderEngine(std::unique_ptr<renderengine::RenderEngine>(mRenderEngine));
- mFlinger.mutableInterceptor().reset(mSurfaceInterceptor);
+ mFlinger.mutableInterceptor() = mSurfaceInterceptor;
injectMockComposer(0);
}
@@ -1481,7 +1481,7 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_0, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(TRANSFORM_FLAGS_ROT_0, compositionState.orientation);
+ EXPECT_EQ(ui::ROTATION_0, compositionState.displaySpace.orientation);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
@@ -1493,7 +1493,7 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_90, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(TRANSFORM_FLAGS_ROT_90, compositionState.orientation);
+ EXPECT_EQ(ui::ROTATION_90, compositionState.displaySpace.orientation);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
// For 90, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
// size width and height swapped
@@ -1508,7 +1508,7 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_180, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(TRANSFORM_FLAGS_ROT_180, compositionState.orientation);
+ EXPECT_EQ(ui::ROTATION_180, compositionState.displaySpace.orientation);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.orientedDisplaySpace.content);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.layerStackSpace.content);
EXPECT_EQ(false, compositionState.needsFiltering);
@@ -1519,7 +1519,7 @@
EXPECT_EQ(ui::Transform(TRANSFORM_FLAGS_ROT_270, mHardwareDisplaySize.width,
mHardwareDisplaySize.height),
compositionState.transform);
- EXPECT_EQ(TRANSFORM_FLAGS_ROT_270, compositionState.orientation);
+ EXPECT_EQ(ui::ROTATION_270, compositionState.displaySpace.orientation);
EXPECT_EQ(Rect(mHardwareDisplaySize), compositionState.displaySpace.content);
// For 270, the orientedDisplaySpaceRect and layerStackSpaceRect have the hardware display
// size width and height swapped
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 93bafb1..98b20e8 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -83,8 +83,8 @@
return nullptr;
}
- std::unique_ptr<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
- return std::make_unique<android::impl::SurfaceInterceptor>(flinger);
+ sp<SurfaceInterceptor> createSurfaceInterceptor(SurfaceFlinger* flinger) override {
+ return new android::impl::SurfaceInterceptor(flinger);
}
sp<StartPropertySetThread> createStartPropertySetThread(bool timestampPropertyValue) override {
@@ -424,7 +424,7 @@
mutableCurrentState().displays.clear();
mutableDrawingState().displays.clear();
mutableEventQueue().reset();
- mutableInterceptor().reset();
+ mutableInterceptor().clear();
mFlinger->mScheduler.reset();
mFlinger->mCompositionEngine->setHwComposer(std::unique_ptr<HWComposer>());
mFlinger->mCompositionEngine->setRenderEngine(
diff --git a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
index ccb7bb9..e2c8a65 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockSurfaceInterceptor.h
@@ -33,6 +33,8 @@
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&));
MOCK_METHOD0(disable, void());
MOCK_METHOD0(isEnabled, bool());
+ MOCK_METHOD1(addTransactionTraceListener, void(const sp<gui::ITransactionTraceListener>&));
+ MOCK_METHOD1(binderDied, void(const wp<IBinder>&));
MOCK_METHOD6(saveTransaction,
void(const Vector<ComposerState>&,
const DefaultKeyedVector<wp<IBinder>, DisplayDeviceState>&,