Merge "inputflinger: Use #pragma once instead of explicit define guards"
diff --git a/cmds/dumpstate/TEST_MAPPING b/cmds/dumpstate/TEST_MAPPING
index 839a2c3..649a13e 100644
--- a/cmds/dumpstate/TEST_MAPPING
+++ b/cmds/dumpstate/TEST_MAPPING
@@ -9,15 +9,15 @@
]
},
{
- "name": "dumpstate_smoke_test"
- },
- {
"name": "dumpstate_test"
}
],
"postsubmit": [
{
"name": "BugreportManagerTestCases"
+ },
+ {
+ "name": "dumpstate_smoke_test"
}
],
"imports": [
diff --git a/include/input/VelocityControl.h b/include/input/VelocityControl.h
index f4c7061..1acc2ae 100644
--- a/include/input/VelocityControl.h
+++ b/include/input/VelocityControl.h
@@ -98,7 +98,7 @@
VelocityControlParameters mParameters;
nsecs_t mLastMovementTime;
- float mRawPositionX, mRawPositionY;
+ VelocityTracker::Position mRawPosition;
VelocityTracker mVelocityTracker;
};
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index 6f2fcf4..886f1f7 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -20,8 +20,6 @@
#include <input/Input.h>
#include <utils/BitSet.h>
#include <utils/Timers.h>
-#include <map>
-#include <set>
namespace android {
@@ -48,14 +46,18 @@
MAX = LEGACY,
};
+ struct Position {
+ float x, y;
+ };
+
struct Estimator {
static const size_t MAX_DEGREE = 4;
// Estimator time base.
nsecs_t time;
- // Polynomial coefficients describing motion.
- float coeff[MAX_DEGREE + 1];
+ // Polynomial coefficients describing motion in X and Y.
+ float xCoeff[MAX_DEGREE + 1], yCoeff[MAX_DEGREE + 1];
// Polynomial degree (number of coefficients), or zero if no information is
// available.
@@ -69,40 +71,14 @@
degree = 0;
confidence = 0;
for (size_t i = 0; i <= MAX_DEGREE; i++) {
- coeff[i] = 0;
+ xCoeff[i] = 0;
+ yCoeff[i] = 0;
}
}
};
- /*
- * Contains all available velocity data from a VelocityTracker.
- */
- struct ComputedVelocity {
- inline std::optional<float> getVelocity(int32_t axis, uint32_t id) const {
- const auto& axisVelocities = mVelocities.find(axis);
- if (axisVelocities == mVelocities.end()) {
- return {};
- }
-
- const auto& axisIdVelocity = axisVelocities->second.find(id);
- if (axisIdVelocity == axisVelocities->second.end()) {
- return {};
- }
-
- return axisIdVelocity->second;
- }
-
- inline void addVelocity(int32_t axis, uint32_t id, float velocity) {
- mVelocities[axis][id] = velocity;
- }
-
- private:
- std::map<int32_t /*axis*/, std::map<int32_t /*pointerId*/, float /*velocity*/>> mVelocities;
- };
-
- // Creates a velocity tracker using the specified strategy for each supported axis.
+ // Creates a velocity tracker using the specified strategy.
// If strategy is not provided, uses the default strategy for the platform.
- // TODO(b/32830165): support axis-specific strategies.
VelocityTracker(const Strategy strategy = Strategy::DEFAULT);
~VelocityTracker();
@@ -116,57 +92,45 @@
void clearPointers(BitSet32 idBits);
// Adds movement information for a set of pointers.
- // The idBits bitfield specifies the pointer ids of the pointers whose data points
+ // The idBits bitfield specifies the pointer ids of the pointers whose positions
// are included in the movement.
- // The positions map contains a mapping of an axis to positions array.
- // The positions arrays contain information for each pointer in order by increasing id.
- // Each array's size should be equal to the number of one bits in idBits.
- void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::map<int32_t, std::vector<float>>& positions);
+ // 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 std::vector<Position>& positions);
// Adds movement information for all pointers in a MotionEvent, including historical samples.
void addMovement(const MotionEvent* event);
- // Returns the velocity of the specified pointer id and axis in position units per second.
- // Returns empty optional if there is insufficient movement information for the pointer, or if
- // the given axis is not supported for velocity tracking.
- std::optional<float> getVelocity(int32_t axis, uint32_t id) const;
+ // Gets the velocity of the specified pointer id in position units per second.
+ // Returns false and sets the velocity components to zero if there is
+ // insufficient movement information for the pointer.
+ bool getVelocity(uint32_t id, float* outVx, float* outVy) const;
- // Populates a ComputedVelocity instance with all available velocity data, using the given units
- // (reference: units == 1 means "per millisecond"), and clamping each velocity between
- // [-maxVelocity, maxVelocity], inclusive.
- void populateComputedVelocity(ComputedVelocity& computedVelocity, int32_t units,
- float maxVelocity);
-
- // Gets an estimator for the recent movements of the specified pointer id for the given axis.
+ // Gets an estimator for the recent movements of the specified pointer id.
// Returns false and clears the estimator if there is no information available
// about the pointer.
- bool getEstimator(int32_t axis, uint32_t id, Estimator* outEstimator) const;
+ bool getEstimator(uint32_t id, Estimator* outEstimator) const;
// Gets the active pointer id, or -1 if none.
inline int32_t getActivePointerId() const { return mActivePointerId; }
+ // Gets a bitset containing all pointer ids from the most recent movement.
+ inline BitSet32 getCurrentPointerIdBits() const { return mCurrentPointerIdBits; }
+
private:
// The default velocity tracker strategy.
// Although other strategies are available for testing and comparison purposes,
// this is the strategy that applications will actually use. Be very careful
// when adjusting the default strategy because it can dramatically affect
// (often in a bad way) the user experience.
- // TODO(b/32830165): define default strategy per axis.
static const Strategy DEFAULT_STRATEGY = Strategy::LSQ2;
- // Set of all axes supported for velocity tracking.
- static const std::set<int32_t> SUPPORTED_AXES;
-
- // Axes specifying location on a 2D plane (i.e. X and Y).
- static const std::set<int32_t> PLANAR_AXES;
-
nsecs_t mLastEventTime;
BitSet32 mCurrentPointerIdBits;
int32_t mActivePointerId;
- std::map<int32_t /*axis*/, std::unique_ptr<VelocityTrackerStrategy>> mStrategies;
+ std::unique_ptr<VelocityTrackerStrategy> mStrategy;
- void configureStrategy(int32_t axis, const Strategy strategy);
+ bool configureStrategy(const Strategy strategy);
static std::unique_ptr<VelocityTrackerStrategy> createStrategy(const Strategy strategy);
};
@@ -185,7 +149,7 @@
virtual void clear() = 0;
virtual void clearPointers(BitSet32 idBits) = 0;
virtual void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) = 0;
+ const std::vector<VelocityTracker::Position>& positions) = 0;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const = 0;
};
@@ -217,7 +181,7 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) override;
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -232,9 +196,11 @@
struct Movement {
nsecs_t eventTime;
BitSet32 idBits;
- float positions[MAX_POINTERS];
+ VelocityTracker::Position positions[MAX_POINTERS];
- inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; }
+ inline const VelocityTracker::Position& getPosition(uint32_t id) const {
+ return positions[idBits.getIndexOfBit(id)];
+ }
};
float chooseWeight(uint32_t index) const;
@@ -258,7 +224,7 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) override;
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -267,15 +233,16 @@
nsecs_t updateTime;
uint32_t degree;
- float pos, vel, accel;
+ float xpos, xvel, xaccel;
+ float ypos, yvel, yaccel;
};
const uint32_t mDegree;
BitSet32 mPointerIdBits;
State mPointerState[MAX_POINTER_ID + 1];
- void initState(State& state, nsecs_t eventTime, float pos) const;
- void updateState(State& state, nsecs_t eventTime, float pos) const;
+ void initState(State& state, nsecs_t eventTime, float xpos, float ypos) const;
+ void updateState(State& state, nsecs_t eventTime, float xpos, float ypos) const;
void populateEstimator(const State& state, VelocityTracker::Estimator* outEstimator) const;
};
@@ -291,7 +258,7 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) override;
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -307,9 +274,11 @@
struct Movement {
nsecs_t eventTime;
BitSet32 idBits;
- float positions[MAX_POINTERS];
+ VelocityTracker::Position positions[MAX_POINTERS];
- inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; }
+ inline const VelocityTracker::Position& getPosition(uint32_t id) const {
+ return positions[idBits.getIndexOfBit(id)];
+ }
};
uint32_t mIndex;
@@ -324,7 +293,7 @@
virtual void clear();
virtual void clearPointers(BitSet32 idBits);
void addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) override;
+ const std::vector<VelocityTracker::Position>& positions) override;
virtual bool getEstimator(uint32_t id, VelocityTracker::Estimator* outEstimator) const;
private:
@@ -339,9 +308,11 @@
struct Movement {
nsecs_t eventTime;
BitSet32 idBits;
- float positions[MAX_POINTERS];
+ VelocityTracker::Position positions[MAX_POINTERS];
- inline float getPosition(uint32_t id) const { return positions[idBits.getIndexOfBit(id)]; }
+ inline const VelocityTracker::Position& getPosition(uint32_t id) const {
+ return positions[idBits.getIndexOfBit(id)];
+ }
};
size_t mIndex;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 2b88852..c4bb6d0 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -76,6 +76,7 @@
srcs: [
"Binder.cpp",
+ "BinderRecordReplay.cpp",
"BpBinder.cpp",
"Debug.cpp",
"FdTrigger.cpp",
@@ -148,7 +149,10 @@
},
debuggable: {
- cflags: ["-DBINDER_RPC_DEV_SERVERS"],
+ cflags: [
+ "-DBINDER_RPC_DEV_SERVERS",
+ "-DBINDER_ENABLE_RECORDING",
+ ],
},
},
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 4029957..481d704 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -21,6 +21,7 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include <binder/BinderRecordReplay.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
@@ -28,7 +29,9 @@
#include <binder/IShellCallback.h>
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
+#include <cutils/compiler.h>
#include <private/android_filesystem_config.h>
+#include <pthread.h>
#include <utils/misc.h>
#include <inttypes.h>
@@ -60,6 +63,12 @@
bool kEnableRpcDevServers = false;
#endif
+#ifdef BINDER_ENABLE_RECORDING
+bool kEnableRecording = true;
+#else
+bool kEnableRecording = false;
+#endif
+
// Log any reply transactions for which the data exceeds this size
#define LOG_REPLIES_OVER_SIZE (300 * 1024)
// ---------------------------------------------------------------------------
@@ -265,11 +274,13 @@
Mutex mLock;
std::set<sp<RpcServerLink>> mRpcServerLinks;
BpBinder::ObjectManager mObjects;
+
+ android::base::unique_fd mRecordingFd;
};
// ---------------------------------------------------------------------------
-BBinder::BBinder() : mExtras(nullptr), mStability(0), mParceled(false) {}
+BBinder::BBinder() : mExtras(nullptr), mStability(0), mParceled(false), mRecordingOn(false) {}
bool BBinder::isBinderAlive() const
{
@@ -281,6 +292,63 @@
return NO_ERROR;
}
+status_t BBinder::startRecordingTransactions(const Parcel& data) {
+ if (!kEnableRecording) {
+ ALOGW("Binder recording disallowed because recording is not enabled");
+ return INVALID_OPERATION;
+ }
+ if (!kEnableKernelIpc) {
+ ALOGW("Binder recording disallowed because kernel binder is not enabled");
+ return INVALID_OPERATION;
+ }
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid != AID_ROOT) {
+ ALOGE("Binder recording not allowed because client %" PRIu32 " is not root", uid);
+ return PERMISSION_DENIED;
+ }
+ Extras* e = getOrCreateExtras();
+ AutoMutex lock(e->mLock);
+ if (mRecordingOn) {
+ LOG(INFO) << "Could not start Binder recording. Another is already in progress.";
+ return INVALID_OPERATION;
+ } else {
+ status_t readStatus = data.readUniqueFileDescriptor(&(e->mRecordingFd));
+ if (readStatus != OK) {
+ return readStatus;
+ }
+ mRecordingOn = true;
+ LOG(INFO) << "Started Binder recording.";
+ return NO_ERROR;
+ }
+}
+
+status_t BBinder::stopRecordingTransactions() {
+ if (!kEnableRecording) {
+ ALOGW("Binder recording disallowed because recording is not enabled");
+ return INVALID_OPERATION;
+ }
+ if (!kEnableKernelIpc) {
+ ALOGW("Binder recording disallowed because kernel binder is not enabled");
+ return INVALID_OPERATION;
+ }
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+ if (uid != AID_ROOT) {
+ ALOGE("Binder recording not allowed because client %" PRIu32 " is not root", uid);
+ return PERMISSION_DENIED;
+ }
+ Extras* e = getOrCreateExtras();
+ AutoMutex lock(e->mLock);
+ if (mRecordingOn) {
+ e->mRecordingFd.reset();
+ mRecordingOn = false;
+ LOG(INFO) << "Stopped Binder recording.";
+ return NO_ERROR;
+ } else {
+ LOG(INFO) << "Could not stop Binder recording. One is not in progress.";
+ return INVALID_OPERATION;
+ }
+}
+
const String16& BBinder::getInterfaceDescriptor() const
{
static StaticString16 sBBinder(u"BBinder");
@@ -303,6 +371,12 @@
case PING_TRANSACTION:
err = pingBinder();
break;
+ case START_RECORDING_TRANSACTION:
+ err = startRecordingTransactions(data);
+ break;
+ case STOP_RECORDING_TRANSACTION:
+ err = stopRecordingTransactions();
+ break;
case EXTENSION_TRANSACTION:
CHECK(reply != nullptr);
err = reply->writeStrongBinder(getExtension());
@@ -329,6 +403,26 @@
}
}
+ if (CC_UNLIKELY(kEnableKernelIpc && mRecordingOn && code != START_RECORDING_TRANSACTION)) {
+ Extras* e = mExtras.load(std::memory_order_acquire);
+ AutoMutex lock(e->mLock);
+ if (mRecordingOn) {
+ Parcel emptyReply;
+ auto transaction =
+ android::binder::debug::RecordedTransaction::fromDetails(code, flags, data,
+ reply ? *reply
+ : emptyReply,
+ err);
+ if (transaction) {
+ if (status_t err = transaction->dumpToFile(e->mRecordingFd); err != NO_ERROR) {
+ LOG(INFO) << "Failed to dump RecordedTransaction to file with error " << err;
+ }
+ } else {
+ LOG(INFO) << "Failed to create RecordedTransaction object.";
+ }
+ }
+ }
+
return err;
}
diff --git a/libs/binder/BinderRecordReplay.cpp b/libs/binder/BinderRecordReplay.cpp
new file mode 100644
index 0000000..90c02a8
--- /dev/null
+++ b/libs/binder/BinderRecordReplay.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 2022, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <binder/BinderRecordReplay.h>
+#include <algorithm>
+
+using android::Parcel;
+using android::base::unique_fd;
+using android::binder::debug::RecordedTransaction;
+
+#define PADDING8(s) ((8 - (s) % 8) % 8)
+
+static_assert(PADDING8(0) == 0);
+static_assert(PADDING8(1) == 7);
+static_assert(PADDING8(7) == 1);
+static_assert(PADDING8(8) == 0);
+
+// Transactions are sequentially recorded to the file descriptor in the following format:
+//
+// RecordedTransaction.TransactionHeader (32 bytes)
+// Sent Parcel data (getDataSize() bytes)
+// padding (enough bytes to align the reply Parcel data to 8 bytes)
+// Reply Parcel data (getReplySize() bytes)
+// padding (enough bytes to align the next header to 8 bytes)
+// [repeats with next transaction]
+//
+// Warning: This format is non-stable
+
+RecordedTransaction::RecordedTransaction(RecordedTransaction&& t) noexcept {
+ mHeader = {t.getCode(), t.getFlags(), t.getDataSize(),
+ t.getReplySize(), t.getReturnedStatus(), t.getVersion()};
+ mSent.setData(t.getDataParcel().data(), t.getDataSize());
+ mReply.setData(t.getReplyParcel().data(), t.getReplySize());
+}
+
+std::optional<RecordedTransaction> RecordedTransaction::fromDetails(uint32_t code, uint32_t flags,
+ const Parcel& dataParcel,
+ const Parcel& replyParcel,
+ status_t err) {
+ RecordedTransaction t;
+ t.mHeader = {code,
+ flags,
+ static_cast<uint64_t>(dataParcel.dataSize()),
+ static_cast<uint64_t>(replyParcel.dataSize()),
+ static_cast<int32_t>(err),
+ dataParcel.isForRpc() ? static_cast<uint32_t>(1) : static_cast<uint32_t>(0)};
+
+ if (t.mSent.setData(dataParcel.data(), t.getDataSize()) != android::NO_ERROR) {
+ LOG(INFO) << "Failed to set sent parcel data.";
+ return std::nullopt;
+ }
+
+ if (t.mReply.setData(replyParcel.data(), t.getReplySize()) != android::NO_ERROR) {
+ LOG(INFO) << "Failed to set reply parcel data.";
+ return std::nullopt;
+ }
+
+ return std::optional<RecordedTransaction>(std::move(t));
+}
+
+std::optional<RecordedTransaction> RecordedTransaction::fromFile(const unique_fd& fd) {
+ RecordedTransaction t;
+ if (!android::base::ReadFully(fd, &t.mHeader, sizeof(mHeader))) {
+ LOG(INFO) << "Failed to read transactionHeader from fd " << fd.get();
+ return std::nullopt;
+ }
+ if (t.getVersion() != 0) {
+ LOG(INFO) << "File corrupted: transaction version is not 0.";
+ return std::nullopt;
+ }
+
+ std::vector<uint8_t> bytes;
+ bytes.resize(t.getDataSize());
+ if (!android::base::ReadFully(fd, bytes.data(), t.getDataSize())) {
+ LOG(INFO) << "Failed to read sent parcel data from fd " << fd.get();
+ return std::nullopt;
+ }
+ if (t.mSent.setData(bytes.data(), t.getDataSize()) != android::NO_ERROR) {
+ LOG(INFO) << "Failed to set sent parcel data.";
+ return std::nullopt;
+ }
+
+ uint8_t padding[7];
+ if (!android::base::ReadFully(fd, padding, PADDING8(t.getDataSize()))) {
+ LOG(INFO) << "Failed to read sent parcel padding from fd " << fd.get();
+ return std::nullopt;
+ }
+ if (std::any_of(padding, padding + 7, [](uint8_t i) { return i != 0; })) {
+ LOG(INFO) << "File corrupted: padding isn't 0.";
+ return std::nullopt;
+ }
+
+ bytes.resize(t.getReplySize());
+ if (!android::base::ReadFully(fd, bytes.data(), t.getReplySize())) {
+ LOG(INFO) << "Failed to read reply parcel data from fd " << fd.get();
+ return std::nullopt;
+ }
+ if (t.mReply.setData(bytes.data(), t.getReplySize()) != android::NO_ERROR) {
+ LOG(INFO) << "Failed to set reply parcel data.";
+ return std::nullopt;
+ }
+
+ if (!android::base::ReadFully(fd, padding, PADDING8(t.getReplySize()))) {
+ LOG(INFO) << "Failed to read parcel padding from fd " << fd.get();
+ return std::nullopt;
+ }
+ if (std::any_of(padding, padding + 7, [](uint8_t i) { return i != 0; })) {
+ LOG(INFO) << "File corrupted: padding isn't 0.";
+ return std::nullopt;
+ }
+
+ return std::optional<RecordedTransaction>(std::move(t));
+}
+
+android::status_t RecordedTransaction::dumpToFile(const unique_fd& fd) const {
+ if (!android::base::WriteFully(fd, &mHeader, sizeof(mHeader))) {
+ LOG(INFO) << "Failed to write transactionHeader to fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+ if (!android::base::WriteFully(fd, mSent.data(), getDataSize())) {
+ LOG(INFO) << "Failed to write sent parcel data to fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+ const uint8_t zeros[7] = {0};
+ if (!android::base::WriteFully(fd, zeros, PADDING8(getDataSize()))) {
+ LOG(INFO) << "Failed to write sent parcel padding to fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+ if (!android::base::WriteFully(fd, mReply.data(), getReplySize())) {
+ LOG(INFO) << "Failed to write reply parcel data to fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+ if (!android::base::WriteFully(fd, zeros, PADDING8(getReplySize()))) {
+ LOG(INFO) << "Failed to write reply parcel padding to fd " << fd.get();
+ return UNKNOWN_ERROR;
+ }
+ return NO_ERROR;
+}
+
+uint32_t RecordedTransaction::getCode() const {
+ return mHeader.code;
+}
+
+uint32_t RecordedTransaction::getFlags() const {
+ return mHeader.flags;
+}
+
+uint64_t RecordedTransaction::getDataSize() const {
+ return mHeader.dataSize;
+}
+
+uint64_t RecordedTransaction::getReplySize() const {
+ return mHeader.replySize;
+}
+
+int32_t RecordedTransaction::getReturnedStatus() const {
+ return mHeader.statusReturned;
+}
+
+uint32_t RecordedTransaction::getVersion() const {
+ return mHeader.version;
+}
+
+const Parcel& RecordedTransaction::getDataParcel() const {
+ return mSent;
+}
+
+const Parcel& RecordedTransaction::getReplyParcel() const {
+ return mReply;
+}
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index d9b7231..54d2445 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -30,6 +30,8 @@
#include "BuildFlags.h"
+#include <android-base/file.h>
+
//#undef ALOGV
//#define ALOGV(...) fprintf(stderr, __VA_ARGS__)
@@ -299,6 +301,18 @@
return transact(PING_TRANSACTION, data, &reply);
}
+status_t BpBinder::startRecordingBinder(const android::base::unique_fd& fd) {
+ Parcel send, reply;
+ send.writeUniqueFileDescriptor(fd);
+ return transact(START_RECORDING_TRANSACTION, send, &reply);
+}
+
+status_t BpBinder::stopRecordingBinder() {
+ Parcel data, reply;
+ data.markForBinder(sp<BpBinder>::fromExisting(this));
+ return transact(STOP_RECORDING_TRANSACTION, data, &reply);
+}
+
status_t BpBinder::dump(int fd, const Vector<String16>& args)
{
Parcel send;
diff --git a/libs/binder/include/binder/Binder.h b/libs/binder/include/binder/Binder.h
index 88d9ca1..08dbd13 100644
--- a/libs/binder/include/binder/Binder.h
+++ b/libs/binder/include/binder/Binder.h
@@ -105,6 +105,12 @@
[[nodiscard]] status_t setRpcClientDebug(android::base::unique_fd clientFd,
const sp<IBinder>& keepAliveBinder);
+ // Start recording transactions to the unique_fd in data.
+ // See BinderRecordReplay.h for more details.
+ [[nodiscard]] status_t startRecordingTransactions(const Parcel& data);
+ // Stop the current recording.
+ [[nodiscard]] status_t stopRecordingTransactions();
+
protected:
virtual ~BBinder();
@@ -131,7 +137,7 @@
friend ::android::internal::Stability;
int16_t mStability;
bool mParceled;
- uint8_t mReserved0;
+ bool mRecordingOn;
#ifdef __LP64__
int32_t mReserved1;
diff --git a/libs/binder/include/binder/BinderRecordReplay.h b/libs/binder/include/binder/BinderRecordReplay.h
new file mode 100644
index 0000000..25ed5e5
--- /dev/null
+++ b/libs/binder/include/binder/BinderRecordReplay.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2022, 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-base/unique_fd.h>
+#include <binder/Parcel.h>
+#include <mutex>
+
+namespace android {
+
+namespace binder::debug {
+
+// Warning: Transactions are sequentially recorded to the file descriptor in a
+// non-stable format. A detailed description of the recording format can be found in
+// BinderRecordReplay.cpp.
+
+class RecordedTransaction {
+public:
+ // Filled with the first transaction from fd.
+ static std::optional<RecordedTransaction> fromFile(const android::base::unique_fd& fd);
+ // Filled with the arguments.
+ static std::optional<RecordedTransaction> fromDetails(uint32_t code, uint32_t flags,
+ const Parcel& data, const Parcel& reply,
+ status_t err);
+ RecordedTransaction(RecordedTransaction&& t) noexcept;
+
+ [[nodiscard]] status_t dumpToFile(const android::base::unique_fd& fd) const;
+
+ uint32_t getCode() const;
+ uint32_t getFlags() const;
+ uint64_t getDataSize() const;
+ uint64_t getReplySize() const;
+ int32_t getReturnedStatus() const;
+ uint32_t getVersion() const;
+ const Parcel& getDataParcel() const;
+ const Parcel& getReplyParcel() const;
+
+private:
+ RecordedTransaction() = default;
+
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wpadded"
+ struct TransactionHeader {
+ uint32_t code = 0;
+ uint32_t flags = 0;
+ uint64_t dataSize = 0;
+ uint64_t replySize = 0;
+ int32_t statusReturned = 0;
+ uint32_t version = 0; // !0 iff Rpc
+ };
+#pragma clang diagnostic pop
+ static_assert(sizeof(TransactionHeader) == 32);
+ static_assert(sizeof(TransactionHeader) % 8 == 0);
+
+ TransactionHeader mHeader;
+ Parcel mSent;
+ Parcel mReply;
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-private-field"
+ uint8_t mReserved[40];
+#pragma clang diagnostic pop
+};
+
+} // namespace binder::debug
+
+} // namespace android
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index 4172cc5..57e103d 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -16,6 +16,7 @@
#pragma once
+#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
#include <utils/Mutex.h>
@@ -89,6 +90,12 @@
std::optional<int32_t> getDebugBinderHandle() const;
+ // Start recording transactions to the unique_fd.
+ // See BinderRecordReplay.h for more details.
+ status_t startRecordingBinder(const android::base::unique_fd& fd);
+ // Stop the current recording.
+ status_t stopRecordingBinder();
+
class ObjectManager {
public:
ObjectManager();
diff --git a/libs/binder/include/binder/IBinder.h b/libs/binder/include/binder/IBinder.h
index 83aaca7..e75d548 100644
--- a/libs/binder/include/binder/IBinder.h
+++ b/libs/binder/include/binder/IBinder.h
@@ -56,6 +56,8 @@
LAST_CALL_TRANSACTION = 0x00ffffff,
PING_TRANSACTION = B_PACK_CHARS('_', 'P', 'N', 'G'),
+ START_RECORDING_TRANSACTION = B_PACK_CHARS('_', 'S', 'R', 'D'),
+ STOP_RECORDING_TRANSACTION = B_PACK_CHARS('_', 'E', 'R', 'D'),
DUMP_TRANSACTION = B_PACK_CHARS('_', 'D', 'M', 'P'),
SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_', 'C', 'M', 'D'),
INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index e460d2c..92d132f 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -605,6 +605,7 @@
shared_libs: [
"libbinder",
"liblog",
+ "libcutils",
"libutils",
"libutilscallstack",
"libbase",
diff --git a/libs/binder/tests/binderAllocationLimits.cpp b/libs/binder/tests/binderAllocationLimits.cpp
index a2ab8ab..55a3916 100644
--- a/libs/binder/tests/binderAllocationLimits.cpp
+++ b/libs/binder/tests/binderAllocationLimits.cpp
@@ -20,6 +20,7 @@
#include <binder/Parcel.h>
#include <binder/RpcServer.h>
#include <binder/RpcSession.h>
+#include <cutils/trace.h>
#include <gtest/gtest.h>
#include <utils/CallStack.h>
@@ -223,5 +224,10 @@
return 1;
}
::testing::InitGoogleTest(&argc, argv);
+
+ // if tracing is enabled, take in one-time cost
+ (void)ATRACE_INIT();
+ (void)ATRACE_GET_ENABLED_TAGS();
+
return RUN_ALL_TESTS();
}
diff --git a/libs/input/VelocityControl.cpp b/libs/input/VelocityControl.cpp
index e2bfb50..6e991e9 100644
--- a/libs/input/VelocityControl.cpp
+++ b/libs/input/VelocityControl.cpp
@@ -44,8 +44,8 @@
void VelocityControl::reset() {
mLastMovementTime = LLONG_MIN;
- mRawPositionX = 0;
- mRawPositionY = 0;
+ mRawPosition.x = 0;
+ mRawPosition.y = 0;
mVelocityTracker.clear();
}
@@ -61,20 +61,17 @@
mLastMovementTime = eventTime;
if (deltaX) {
- mRawPositionX += *deltaX;
+ mRawPosition.x += *deltaX;
}
if (deltaY) {
- mRawPositionY += *deltaY;
+ mRawPosition.y += *deltaY;
}
- mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)),
- {{AMOTION_EVENT_AXIS_X, {mRawPositionX}},
- {AMOTION_EVENT_AXIS_Y, {mRawPositionY}}});
+ mVelocityTracker.addMovement(eventTime, BitSet32(BitSet32::valueForBit(0)), {mRawPosition});
- std::optional<float> vx = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, 0);
- std::optional<float> vy = mVelocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, 0);
+ float vx, vy;
float scale = mParameters.scale;
- if (vx && vy) {
- float speed = hypotf(*vx, *vy) * scale;
+ if (mVelocityTracker.getVelocity(0, &vx, &vy)) {
+ float speed = hypotf(vx, vy) * scale;
if (speed >= mParameters.highThreshold) {
// Apply full acceleration above the high speed threshold.
scale *= mParameters.acceleration;
@@ -88,9 +85,10 @@
if (DEBUG_ACCELERATION) {
ALOGD("VelocityControl(%0.3f, %0.3f, %0.3f, %0.3f): "
- "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
- mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
- mParameters.acceleration, *vx, *vy, speed, scale / mParameters.scale);
+ "vx=%0.3f, vy=%0.3f, speed=%0.3f, accel=%0.3f",
+ mParameters.scale, mParameters.lowThreshold, mParameters.highThreshold,
+ mParameters.acceleration,
+ vx, vy, speed, scale / mParameters.scale);
}
} else {
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index 4f91af1..76aaf61 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -125,39 +125,29 @@
// --- VelocityTracker ---
-const std::set<int32_t> VelocityTracker::SUPPORTED_AXES = {AMOTION_EVENT_AXIS_X,
- AMOTION_EVENT_AXIS_Y};
-
-const std::set<int32_t> VelocityTracker::PLANAR_AXES = {AMOTION_EVENT_AXIS_X, AMOTION_EVENT_AXIS_Y};
-
VelocityTracker::VelocityTracker(const Strategy strategy)
: mLastEventTime(0), mCurrentPointerIdBits(0), mActivePointerId(-1) {
- // Configure the strategy for each axis.
- for (int32_t axis : SUPPORTED_AXES) {
- configureStrategy(axis, strategy);
+ // Configure the strategy.
+ if (!configureStrategy(strategy)) {
+ ALOGE("Unrecognized velocity tracker strategy %" PRId32 ".", strategy);
+ if (!configureStrategy(VelocityTracker::DEFAULT_STRATEGY)) {
+ LOG_ALWAYS_FATAL("Could not create the default velocity tracker strategy '%" PRId32
+ "'!",
+ strategy);
+ }
}
}
VelocityTracker::~VelocityTracker() {
}
-void VelocityTracker::configureStrategy(int32_t axis, const Strategy strategy) {
- std::unique_ptr<VelocityTrackerStrategy> createdStrategy;
-
+bool VelocityTracker::configureStrategy(Strategy strategy) {
if (strategy == VelocityTracker::Strategy::DEFAULT) {
- createdStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY);
+ mStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY);
} else {
- createdStrategy = createStrategy(strategy);
+ mStrategy = createStrategy(strategy);
}
-
- if (createdStrategy == nullptr) {
- ALOGE("Unrecognized velocity tracker strategy %" PRId32 ".", strategy);
- createdStrategy = createStrategy(VelocityTracker::DEFAULT_STRATEGY);
- LOG_ALWAYS_FATAL_IF(createdStrategy == nullptr,
- "Could not create the default velocity tracker strategy '%" PRId32 "'!",
- strategy);
- }
- mStrategies[axis] = std::move(createdStrategy);
+ return mStrategy != nullptr;
}
std::unique_ptr<VelocityTrackerStrategy> VelocityTracker::createStrategy(
@@ -211,9 +201,8 @@
void VelocityTracker::clear() {
mCurrentPointerIdBits.clear();
mActivePointerId = -1;
- for (int32_t axis : SUPPORTED_AXES) {
- mStrategies[axis]->clear();
- }
+
+ mStrategy->clear();
}
void VelocityTracker::clearPointers(BitSet32 idBits) {
@@ -224,13 +213,14 @@
mActivePointerId = !remainingIdBits.isEmpty() ? remainingIdBits.firstMarkedBit() : -1;
}
- for (int32_t axis : SUPPORTED_AXES) {
- mStrategies[axis]->clearPointers(idBits);
- }
+ mStrategy->clearPointers(idBits);
}
void VelocityTracker::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::map<int32_t /*axis*/, std::vector<float>>& positions) {
+ 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();
}
@@ -242,9 +232,7 @@
// We have not received any movements for too long. Assume that all pointers
// have stopped.
- for (const auto& [_, strategy] : mStrategies) {
- strategy->clear();
- }
+ mStrategy->clear();
}
mLastEventTime = eventTime;
@@ -253,37 +241,29 @@
mActivePointerId = idBits.isEmpty() ? -1 : idBits.firstMarkedBit();
}
- for (const auto& [axis, positionValues] : positions) {
- LOG_ALWAYS_FATAL_IF(idBits.count() != positionValues.size(),
- "Mismatching number of pointers, idBits=%" PRIu32 ", positions=%zu",
- idBits.count(), positionValues.size());
- mStrategies[axis]->addMovement(eventTime, idBits, positionValues);
- }
+ mStrategy->addMovement(eventTime, idBits, positions);
if (DEBUG_VELOCITY) {
ALOGD("VelocityTracker: addMovement eventTime=%" PRId64
", idBits=0x%08x, activePointerId=%d",
eventTime, idBits.value, mActivePointerId);
- for (const auto& positionsEntry : positions) {
- for (BitSet32 iterBits(idBits); !iterBits.isEmpty();) {
- uint32_t id = iterBits.firstMarkedBit();
- uint32_t index = idBits.getIndexOfBit(id);
- iterBits.clearBit(id);
- Estimator estimator;
- getEstimator(positionsEntry.first, id, &estimator);
- ALOGD(" %d: axis=%d, position=%0.3f, "
- "estimator (degree=%d, coeff=%s, confidence=%f)",
- id, positionsEntry.first, positionsEntry.second[index], int(estimator.degree),
- vectorToString(estimator.coeff, estimator.degree + 1).c_str(),
- estimator.confidence);
- }
+ for (BitSet32 iterBits(idBits); !iterBits.isEmpty();) {
+ uint32_t id = iterBits.firstMarkedBit();
+ uint32_t index = idBits.getIndexOfBit(id);
+ iterBits.clearBit(id);
+ Estimator estimator;
+ getEstimator(id, &estimator);
+ ALOGD(" %d: position (%0.3f, %0.3f), "
+ "estimator (degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f)",
+ id, positions[index].x, positions[index].y, int(estimator.degree),
+ vectorToString(estimator.xCoeff, estimator.degree + 1).c_str(),
+ vectorToString(estimator.yCoeff, estimator.degree + 1).c_str(),
+ estimator.confidence);
}
}
}
void VelocityTracker::addMovement(const MotionEvent* event) {
- // Stores data about which axes to process based on the incoming motion event.
- std::set<int32_t> axesToProcess;
int32_t actionMasked = event->getActionMasked();
switch (actionMasked) {
@@ -291,9 +271,6 @@
case AMOTION_EVENT_ACTION_HOVER_ENTER:
// Clear all pointers on down before adding the new movement.
clear();
- for (int32_t axis : PLANAR_AXES) {
- axesToProcess.insert(axis);
- }
break;
case AMOTION_EVENT_ACTION_POINTER_DOWN: {
// Start a new movement trace for a pointer that just went down.
@@ -302,16 +279,10 @@
BitSet32 downIdBits;
downIdBits.markBit(event->getPointerId(event->getActionIndex()));
clearPointers(downIdBits);
- for (int32_t axis : PLANAR_AXES) {
- axesToProcess.insert(axis);
- }
break;
}
case AMOTION_EVENT_ACTION_MOVE:
case AMOTION_EVENT_ACTION_HOVER_MOVE:
- for (int32_t axis : PLANAR_AXES) {
- axesToProcess.insert(axis);
- }
break;
case AMOTION_EVENT_ACTION_POINTER_UP:
case AMOTION_EVENT_ACTION_UP: {
@@ -322,9 +293,7 @@
toString(delaySinceLastEvent).c_str());
// We have not received any movements for too long. Assume that all pointers
// have stopped.
- for (int32_t axis : PLANAR_AXES) {
- mStrategies[axis]->clear();
- }
+ mStrategy->clear();
}
// These actions because they do not convey any new information about
// pointer movement. We also want to preserve the last known velocity of the pointers.
@@ -356,54 +325,37 @@
pointerIndex[i] = idBits.getIndexOfBit(event->getPointerId(i));
}
- std::map<int32_t, std::vector<float>> positions;
- for (int32_t axis : axesToProcess) {
- positions[axis].resize(pointerCount);
- }
+ std::vector<Position> positions;
+ positions.resize(pointerCount);
size_t historySize = event->getHistorySize();
for (size_t h = 0; h <= historySize; h++) {
nsecs_t eventTime = event->getHistoricalEventTime(h);
- for (int32_t axis : axesToProcess) {
- for (size_t i = 0; i < pointerCount; i++) {
- positions[axis][pointerIndex[i]] = event->getHistoricalAxisValue(axis, i, h);
- }
+ for (size_t i = 0; i < pointerCount; i++) {
+ uint32_t index = pointerIndex[i];
+ positions[index].x = event->getHistoricalX(i, h);
+ positions[index].y = event->getHistoricalY(i, h);
}
addMovement(eventTime, idBits, positions);
}
}
-std::optional<float> VelocityTracker::getVelocity(int32_t axis, uint32_t id) const {
+bool VelocityTracker::getVelocity(uint32_t id, float* outVx, float* outVy) const {
Estimator estimator;
- bool validVelocity = getEstimator(axis, id, &estimator) && estimator.degree >= 1;
- if (validVelocity) {
- return estimator.coeff[1];
+ if (getEstimator(id, &estimator) && estimator.degree >= 1) {
+ *outVx = estimator.xCoeff[1];
+ *outVy = estimator.yCoeff[1];
+ return true;
}
- return {};
+ *outVx = 0;
+ *outVy = 0;
+ return false;
}
-void VelocityTracker::populateComputedVelocity(ComputedVelocity& computedVelocity, int32_t units,
- float maxVelocity) {
- for (int32_t axis : SUPPORTED_AXES) {
- BitSet32 copyIdBits = BitSet32(mCurrentPointerIdBits);
- while (!copyIdBits.isEmpty()) {
- uint32_t id = copyIdBits.clearFirstMarkedBit();
- std::optional<float> velocity = getVelocity(axis, id);
- if (velocity) {
- float adjustedVelocity =
- std::clamp(*velocity * units / 1000, -maxVelocity, maxVelocity);
- computedVelocity.addVelocity(axis, id, adjustedVelocity);
- }
- }
- }
+bool VelocityTracker::getEstimator(uint32_t id, Estimator* outEstimator) const {
+ return mStrategy->getEstimator(id, outEstimator);
}
-bool VelocityTracker::getEstimator(int32_t axis, uint32_t id, Estimator* outEstimator) const {
- if (SUPPORTED_AXES.find(axis) == SUPPORTED_AXES.end()) {
- return false;
- }
- return mStrategies.at(axis)->getEstimator(id, outEstimator);
-}
// --- LeastSquaresVelocityTrackerStrategy ---
@@ -426,8 +378,9 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void LeastSquaresVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& 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
@@ -674,7 +627,8 @@
outEstimator->clear();
// Iterate over movement samples in reverse time order and collect samples.
- std::vector<float> positions;
+ std::vector<float> x;
+ std::vector<float> y;
std::vector<float> w;
std::vector<float> time;
@@ -691,13 +645,15 @@
break;
}
- positions.push_back(movement.getPosition(id));
+ const VelocityTracker::Position& position = movement.getPosition(id);
+ 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 (positions.size() < HISTORY_SIZE);
+ } while (x.size() < HISTORY_SIZE);
- const size_t m = positions.size();
+ const size_t m = x.size();
if (m == 0) {
return false; // no data
}
@@ -710,36 +666,39 @@
if (degree == 2 && mWeighting == WEIGHTING_NONE) {
// Optimize unweighted, quadratic polynomial fit
- std::optional<std::array<float, 3>> coeff =
- solveUnweightedLeastSquaresDeg2(time, positions);
- if (coeff) {
+ 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;
outEstimator->confidence = 1;
for (size_t i = 0; i <= outEstimator->degree; i++) {
- outEstimator->coeff[i] = (*coeff)[i];
+ outEstimator->xCoeff[i] = (*xCoeff)[i];
+ outEstimator->yCoeff[i] = (*yCoeff)[i];
}
return true;
}
} else if (degree >= 1) {
// General case for an Nth degree polynomial fit
- float det;
+ float xdet, ydet;
uint32_t n = degree + 1;
- if (solveLeastSquares(time, positions, w, n, outEstimator->coeff, &det)) {
+ 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 = det;
+ outEstimator->confidence = xdet * ydet;
- ALOGD_IF(DEBUG_STRATEGY, "estimate: degree=%d, coeff=%s, confidence=%f",
- int(outEstimator->degree), vectorToString(outEstimator->coeff, n).c_str(),
- outEstimator->confidence);
+ ALOGD_IF(DEBUG_STRATEGY, "estimate: degree=%d, xCoeff=%s, yCoeff=%s, confidence=%f",
+ int(outEstimator->degree), vectorToString(outEstimator->xCoeff, n).c_str(),
+ vectorToString(outEstimator->yCoeff, n).c_str(), outEstimator->confidence);
return true;
}
}
// No velocity data available for this pointer, but we do have its current position.
- outEstimator->coeff[0] = positions[0];
+ outEstimator->xCoeff[0] = x[0];
+ outEstimator->yCoeff[0] = y[0];
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = 0;
outEstimator->confidence = 1;
@@ -831,17 +790,18 @@
mPointerIdBits.value &= ~idBits.value;
}
-void IntegratingVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& 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();
State& state = mPointerState[id];
- const float position = positions[index++];
+ const VelocityTracker::Position& position = positions[index++];
if (mPointerIdBits.hasBit(id)) {
- updateState(state, eventTime, position);
+ updateState(state, eventTime, position.x, position.y);
} else {
- initState(state, eventTime, position);
+ initState(state, eventTime, position.x, position.y);
}
}
@@ -861,18 +821,21 @@
return false;
}
-void IntegratingVelocityTrackerStrategy::initState(State& state, nsecs_t eventTime,
- float pos) const {
+void IntegratingVelocityTrackerStrategy::initState(State& state,
+ nsecs_t eventTime, float xpos, float ypos) const {
state.updateTime = eventTime;
state.degree = 0;
- state.pos = pos;
- state.accel = 0;
- state.vel = 0;
+ state.xpos = xpos;
+ state.xvel = 0;
+ state.xaccel = 0;
+ state.ypos = ypos;
+ state.yvel = 0;
+ state.yaccel = 0;
}
-void IntegratingVelocityTrackerStrategy::updateState(State& state, nsecs_t eventTime,
- float pos) const {
+void IntegratingVelocityTrackerStrategy::updateState(State& state,
+ nsecs_t eventTime, float xpos, float ypos) const {
const nsecs_t MIN_TIME_DELTA = 2 * NANOS_PER_MS;
const float FILTER_TIME_CONSTANT = 0.010f; // 10 milliseconds
@@ -883,26 +846,34 @@
float dt = (eventTime - state.updateTime) * 0.000000001f;
state.updateTime = eventTime;
- float vel = (pos - state.pos) / dt;
+ float xvel = (xpos - state.xpos) / dt;
+ float yvel = (ypos - state.ypos) / dt;
if (state.degree == 0) {
- state.vel = vel;
+ state.xvel = xvel;
+ state.yvel = yvel;
state.degree = 1;
} else {
float alpha = dt / (FILTER_TIME_CONSTANT + dt);
if (mDegree == 1) {
- state.vel += (vel - state.vel) * alpha;
+ state.xvel += (xvel - state.xvel) * alpha;
+ state.yvel += (yvel - state.yvel) * alpha;
} else {
- float accel = (vel - state.vel) / dt;
+ float xaccel = (xvel - state.xvel) / dt;
+ float yaccel = (yvel - state.yvel) / dt;
if (state.degree == 1) {
- state.accel = accel;
+ state.xaccel = xaccel;
+ state.yaccel = yaccel;
state.degree = 2;
} else {
- state.accel += (accel - state.accel) * alpha;
+ state.xaccel += (xaccel - state.xaccel) * alpha;
+ state.yaccel += (yaccel - state.yaccel) * alpha;
}
- state.vel += (state.accel * dt) * alpha;
+ state.xvel += (state.xaccel * dt) * alpha;
+ state.yvel += (state.yaccel * dt) * alpha;
}
}
- state.pos = pos;
+ state.xpos = xpos;
+ state.ypos = ypos;
}
void IntegratingVelocityTrackerStrategy::populateEstimator(const State& state,
@@ -910,9 +881,12 @@
outEstimator->time = state.updateTime;
outEstimator->confidence = 1.0f;
outEstimator->degree = state.degree;
- outEstimator->coeff[0] = state.pos;
- outEstimator->coeff[1] = state.vel;
- outEstimator->coeff[2] = state.accel / 2;
+ outEstimator->xCoeff[0] = state.xpos;
+ outEstimator->xCoeff[1] = state.xvel;
+ outEstimator->xCoeff[2] = state.xaccel / 2;
+ outEstimator->yCoeff[0] = state.ypos;
+ outEstimator->yCoeff[1] = state.yvel;
+ outEstimator->yCoeff[2] = state.yaccel / 2;
}
@@ -935,8 +909,9 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void LegacyVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& positions) {
+void LegacyVelocityTrackerStrategy::addMovement(
+ nsecs_t eventTime, BitSet32 idBits,
+ const std::vector<VelocityTracker::Position>& positions) {
if (++mIndex == HISTORY_SIZE) {
mIndex = 0;
}
@@ -984,11 +959,12 @@
// overestimate the velocity at that time point. Most samples might be measured
// 16ms apart but some consecutive samples could be only 0.5sm apart because
// the hardware or driver reports them irregularly or in bursts.
- float accumV = 0;
+ float accumVx = 0;
+ float accumVy = 0;
uint32_t index = oldestIndex;
uint32_t samplesUsed = 0;
const Movement& oldestMovement = mMovements[oldestIndex];
- float oldestPosition = oldestMovement.getPosition(id);
+ const VelocityTracker::Position& oldestPosition = oldestMovement.getPosition(id);
nsecs_t lastDuration = 0;
while (numTouches-- > 1) {
@@ -1002,22 +978,26 @@
// the velocity. Consequently, we impose a minimum duration constraint on the
// samples that we include in the calculation.
if (duration >= MIN_DURATION) {
- float position = movement.getPosition(id);
+ const VelocityTracker::Position& position = movement.getPosition(id);
float scale = 1000000000.0f / duration; // one over time delta in seconds
- float v = (position - oldestPosition) * scale;
- accumV = (accumV * lastDuration + v * duration) / (duration + lastDuration);
+ float vx = (position.x - oldestPosition.x) * scale;
+ float vy = (position.y - oldestPosition.y) * scale;
+ accumVx = (accumVx * lastDuration + vx * duration) / (duration + lastDuration);
+ accumVy = (accumVy * lastDuration + vy * duration) / (duration + lastDuration);
lastDuration = duration;
samplesUsed += 1;
}
}
// Report velocity.
- float newestPosition = newestMovement.getPosition(id);
+ const VelocityTracker::Position& newestPosition = newestMovement.getPosition(id);
outEstimator->time = newestMovement.eventTime;
outEstimator->confidence = 1;
- outEstimator->coeff[0] = newestPosition;
+ outEstimator->xCoeff[0] = newestPosition.x;
+ outEstimator->yCoeff[0] = newestPosition.y;
if (samplesUsed) {
- outEstimator->coeff[1] = accumV;
+ outEstimator->xCoeff[1] = accumVx;
+ outEstimator->yCoeff[1] = accumVy;
outEstimator->degree = 1;
} else {
outEstimator->degree = 0;
@@ -1044,8 +1024,9 @@
mMovements[mIndex].idBits = remainingIdBits;
}
-void ImpulseVelocityTrackerStrategy::addMovement(nsecs_t eventTime, BitSet32 idBits,
- const std::vector<float>& 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
@@ -1182,7 +1163,8 @@
outEstimator->clear();
// Iterate over movement samples in reverse time order and collect samples.
- float positions[HISTORY_SIZE];
+ float x[HISTORY_SIZE];
+ float y[HISTORY_SIZE];
nsecs_t time[HISTORY_SIZE];
size_t m = 0; // number of points that will be used for fitting
size_t index = mIndex;
@@ -1198,7 +1180,9 @@
break;
}
- positions[m] = movement.getPosition(id);
+ const VelocityTracker::Position& position = movement.getPosition(id);
+ x[m] = position.x;
+ y[m] = position.y;
time[m] = movement.eventTime;
index = (index == 0 ? HISTORY_SIZE : index) - 1;
} while (++m < HISTORY_SIZE);
@@ -1206,30 +1190,33 @@
if (m == 0) {
return false; // no data
}
- outEstimator->coeff[0] = 0;
- outEstimator->coeff[1] = calculateImpulseVelocity(time, positions, m);
- outEstimator->coeff[2] = 0;
-
+ outEstimator->xCoeff[0] = 0;
+ outEstimator->yCoeff[0] = 0;
+ outEstimator->xCoeff[1] = calculateImpulseVelocity(time, x, m);
+ outEstimator->yCoeff[1] = calculateImpulseVelocity(time, y, m);
+ outEstimator->xCoeff[2] = 0;
+ outEstimator->yCoeff[2] = 0;
outEstimator->time = newestMovement.eventTime;
outEstimator->degree = 2; // similar results to 2nd degree fit
outEstimator->confidence = 1;
- ALOGD_IF(DEBUG_STRATEGY, "velocity: %.1f", outEstimator->coeff[1]);
+ ALOGD_IF(DEBUG_STRATEGY, "velocity: (%.1f, %.1f)", outEstimator->xCoeff[1],
+ outEstimator->yCoeff[1]);
if (DEBUG_IMPULSE) {
// TODO(b/134179997): delete this block once the switch to 'impulse' is complete.
- // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons.
- // X axis chosen arbitrarily for velocity comparisons.
+ // Calculate the lsq2 velocity for the same inputs to allow runtime comparisons
VelocityTracker lsq2(VelocityTracker::Strategy::LSQ2);
BitSet32 idBits;
const uint32_t pointerId = 0;
idBits.markBit(pointerId);
for (ssize_t i = m - 1; i >= 0; i--) {
- lsq2.addMovement(time[i], idBits, {{AMOTION_EVENT_AXIS_X, {positions[i]}}});
+ lsq2.addMovement(time[i], idBits, {{x[i], y[i]}});
}
- std::optional<float> v = lsq2.getVelocity(AMOTION_EVENT_AXIS_X, pointerId);
- if (v) {
- ALOGD("lsq2 velocity: %.1f", *v);
+ float outVx = 0, outVy = 0;
+ const bool computed = lsq2.getVelocity(pointerId, &outVx, &outVy);
+ if (computed) {
+ ALOGD("lsq2 velocity: (%.1f, %.1f)", outVx, outVy);
} else {
ALOGD("lsq2 velocity: could not compute velocity");
}
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 0a37318..4a445de 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -16,10 +16,9 @@
#define LOG_TAG "VelocityTracker_test"
-#include <math.h>
#include <array>
#include <chrono>
-#include <limits>
+#include <math.h>
#include <android-base/stringprintf.h>
#include <attestation/HmacKeyManager.h>
@@ -199,13 +198,25 @@
const std::vector<MotionEventEntry>& motions, int32_t axis,
float targetVelocity, uint32_t pointerId = DEFAULT_POINTER_ID) {
VelocityTracker vt(strategy);
+ float Vx, Vy;
std::vector<MotionEvent> events = createMotionEventStream(motions);
for (MotionEvent event : events) {
vt.addMovement(&event);
}
- checkVelocity(vt.getVelocity(axis, pointerId).value_or(0), targetVelocity);
+ vt.getVelocity(pointerId, &Vx, &Vy);
+
+ switch (axis) {
+ case AMOTION_EVENT_AXIS_X:
+ checkVelocity(Vx, targetVelocity);
+ break;
+ case AMOTION_EVENT_AXIS_Y:
+ checkVelocity(Vy, targetVelocity);
+ break;
+ default:
+ FAIL() << "Axis must be either AMOTION_EVENT_AXIS_X or AMOTION_EVENT_AXIS_Y";
+ }
}
static void computeAndCheckQuadraticEstimate(const std::vector<MotionEventEntry>& motions,
@@ -215,99 +226,17 @@
for (MotionEvent event : events) {
vt.addMovement(&event);
}
- VelocityTracker::Estimator estimatorX;
- VelocityTracker::Estimator estimatorY;
- EXPECT_TRUE(vt.getEstimator(AMOTION_EVENT_AXIS_X, 0, &estimatorX));
- EXPECT_TRUE(vt.getEstimator(AMOTION_EVENT_AXIS_Y, 0, &estimatorY));
+ VelocityTracker::Estimator estimator;
+ EXPECT_TRUE(vt.getEstimator(0, &estimator));
for (size_t i = 0; i< coefficients.size(); i++) {
- checkCoefficient(estimatorX.coeff[i], coefficients[i]);
- checkCoefficient(estimatorY.coeff[i], coefficients[i]);
+ checkCoefficient(estimator.xCoeff[i], coefficients[i]);
+ checkCoefficient(estimator.yCoeff[i], coefficients[i]);
}
}
/*
* ================== VelocityTracker tests generated manually =====================================
*/
-TEST_F(VelocityTrackerTest, TestComputedVelocity) {
- VelocityTracker::ComputedVelocity computedVelocity;
-
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 0 /*id*/, 200 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 26U /*id*/, 400 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, 27U /*id*/, 650 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID, 750 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 0 /*id*/, 1000 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 26U /*id*/, 2000 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, 27U /*id*/, 3000 /*velocity*/);
- computedVelocity.addVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID, 4000 /*velocity*/);
-
- // Check the axes/indices with velocity.
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 0U /*id*/)), 200);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 26U /*id*/)), 400);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, 27U /*id*/)), 650);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID)), 750);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 0U /*id*/)), 1000);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 26U /*id*/)), 2000);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, 27U /*id*/)), 3000);
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, MAX_POINTER_ID)), 4000);
- for (uint32_t id = 0; id < 32; id++) {
- // Since no data was added for AXIS_SCROLL, expect empty value for the axis for any id.
- EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_SCROLL, id))
- << "Empty scroll data expected at id=" << id;
- if (id == 0 || id == 26U || id == 27U || id == MAX_POINTER_ID) {
- // Already checked above; continue.
- continue;
- }
- // No data was added to X/Y for this id, expect empty value.
- EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, id))
- << "Empty X data expected at id=" << id;
- EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, id))
- << "Empty Y data expected at id=" << id;
- }
- // Out-of-bounds ids should given empty values.
- EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, -1));
- EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, MAX_POINTER_ID + 1));
-}
-
-TEST_F(VelocityTrackerTest, TestPopulateComputedVelocity) {
- std::vector<MotionEventEntry> motions = {
- {235089067457000ns, {{528.00, 0}}}, {235089084684000ns, {{527.00, 0}}},
- {235089093349000ns, {{527.00, 0}}}, {235089095677625ns, {{527.00, 0}}},
- {235089101859000ns, {{527.00, 0}}}, {235089110378000ns, {{528.00, 0}}},
- {235089112497111ns, {{528.25, 0}}}, {235089118760000ns, {{531.00, 0}}},
- {235089126686000ns, {{535.00, 0}}}, {235089129316820ns, {{536.33, 0}}},
- {235089135199000ns, {{540.00, 0}}}, {235089144297000ns, {{546.00, 0}}},
- {235089146136443ns, {{547.21, 0}}}, {235089152923000ns, {{553.00, 0}}},
- {235089160784000ns, {{559.00, 0}}}, {235089162955851ns, {{560.66, 0}}},
- {235089162955851ns, {{560.66, 0}}}, // ACTION_UP
- };
- VelocityTracker vt(VelocityTracker::Strategy::IMPULSE);
- std::vector<MotionEvent> events = createMotionEventStream(motions);
- for (const MotionEvent& event : events) {
- vt.addMovement(&event);
- }
-
- float maxFloat = std::numeric_limits<float>::max();
- VelocityTracker::ComputedVelocity computedVelocity;
- vt.populateComputedVelocity(computedVelocity, 1000 /* units */, maxFloat);
- checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)),
- 764.345703);
-
- // Expect X velocity to be scaled with respective to provided units.
- vt.populateComputedVelocity(computedVelocity, 1000000 /* units */, maxFloat);
- checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)),
- 764345.703);
-
- // Expect X velocity to be clamped by provided max velocity.
- vt.populateComputedVelocity(computedVelocity, 1000000 /* units */, 1000);
- checkVelocity(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_X, DEFAULT_POINTER_ID)), 1000);
-
- // All 0 data for Y; expect 0 velocity.
- EXPECT_EQ(*(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_Y, DEFAULT_POINTER_ID)), 0);
-
- // No data for scroll-axis; expect empty velocity.
- EXPECT_FALSE(computedVelocity.getVelocity(AMOTION_EVENT_AXIS_SCROLL, DEFAULT_POINTER_ID));
-}
-
TEST_F(VelocityTrackerTest, ThreePointsPositiveVelocityTest) {
// Same coordinate is reported 2 times in a row
// It is difficult to determine the correct answer here, but at least the direction
diff --git a/libs/sensor/ISensorServer.cpp b/libs/sensor/ISensorServer.cpp
index a6cacad..78f692b 100644
--- a/libs/sensor/ISensorServer.cpp
+++ b/libs/sensor/ISensorServer.cpp
@@ -22,12 +22,12 @@
#include <cutils/native_handle.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
-#include <utils/Vector.h>
#include <utils/Timers.h>
+#include <utils/Vector.h>
-#include <binder/Parcel.h>
#include <binder/IInterface.h>
#include <binder/IResultReceiver.h>
+#include <binder/Parcel.h>
#include <sensor/Sensor.h>
#include <sensor/ISensorEventConnection.h>
@@ -205,9 +205,10 @@
if (resource == nullptr) {
return BAD_VALUE;
}
+ native_handle_set_fdsan_tag(resource);
sp<ISensorEventConnection> ch =
createSensorDirectConnection(opPackageName, size, type, format, resource);
- native_handle_close(resource);
+ native_handle_close_with_tag(resource);
native_handle_delete(resource);
reply->writeStrongBinder(IInterface::asBinder(ch));
return NO_ERROR;
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 8c241f2..539e24a 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -2712,18 +2712,17 @@
// Update the velocity tracker.
{
- std::vector<float> positionsX;
- std::vector<float> positionsY;
+ 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);
- positionsX.push_back(pointer.x * mPointerXMovementScale);
- positionsY.push_back(pointer.y * mPointerYMovementScale);
+ float x = pointer.x * mPointerXMovementScale;
+ float y = pointer.y * mPointerYMovementScale;
+ positions.push_back({x, y});
}
mPointerGesture.velocityTracker.addMovement(when, mCurrentCookedState.fingerIdBits,
- {{AMOTION_EVENT_AXIS_X, positionsX},
- {AMOTION_EVENT_AXIS_Y, positionsY}});
+ positions);
}
// If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning
@@ -2830,12 +2829,9 @@
float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed;
for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty();) {
uint32_t id = idBits.clearFirstMarkedBit();
- std::optional<float> vx =
- mPointerGesture.velocityTracker.getVelocity(AMOTION_EVENT_AXIS_X, id);
- std::optional<float> vy =
- mPointerGesture.velocityTracker.getVelocity(AMOTION_EVENT_AXIS_Y, id);
- if (vx && vy) {
- float speed = hypotf(*vx, *vy);
+ float vx, vy;
+ if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) {
+ float speed = hypotf(vx, vy);
if (speed > bestSpeed) {
bestId = id;
bestSpeed = speed;
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index de050e0..10ca990 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -39,7 +39,6 @@
#include <thread>
using namespace android::hardware::sensors;
-using android::hardware::Return;
using android::util::ProtoOutputStream;
namespace android {
diff --git a/services/sensorservice/SensorDirectConnection.cpp b/services/sensorservice/SensorDirectConnection.cpp
index 2dd12e9..291c770 100644
--- a/services/sensorservice/SensorDirectConnection.cpp
+++ b/services/sensorservice/SensorDirectConnection.cpp
@@ -14,11 +14,11 @@
* limitations under the License.
*/
-#include "SensorDevice.h"
#include "SensorDirectConnection.h"
#include <android/util/ProtoOutputStream.h>
#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <hardware/sensors.h>
+#include "SensorDevice.h"
#define UNUSED(x) (void)(x)
@@ -51,7 +51,7 @@
stopAll();
mService->cleanupConnection(this);
if (mMem.handle != nullptr) {
- native_handle_close(mMem.handle);
+ native_handle_close_with_tag(mMem.handle);
native_handle_delete(const_cast<struct native_handle*>(mMem.handle));
}
mDestroyed = true;
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index e0a4f03..21d6b6b 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -16,7 +16,6 @@
#include <android-base/strings.h>
#include <android/content/pm/IPackageManagerNative.h>
#include <android/util/ProtoOutputStream.h>
-#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <binder/ActivityManager.h>
#include <binder/BinderService.h>
#include <binder/IServiceManager.h>
@@ -25,6 +24,7 @@
#include <cutils/ashmem.h>
#include <cutils/misc.h>
#include <cutils/properties.h>
+#include <frameworks/base/core/proto/android/service/sensor_service.proto.h>
#include <hardware/sensors.h>
#include <hardware_legacy/power.h>
#include <log/log.h>
@@ -1475,6 +1475,7 @@
if (!clone) {
return nullptr;
}
+ native_handle_set_fdsan_tag(clone);
sp<SensorDirectConnection> conn;
SensorDevice& dev(SensorDevice::getInstance());
@@ -1488,7 +1489,7 @@
}
if (conn == nullptr) {
- native_handle_close(clone);
+ native_handle_close_with_tag(clone);
native_handle_delete(clone);
} else {
// add to list of direct connections
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
index caf7f03..b00d1a7 100644
--- a/services/sensorservice/tests/sensorservicetest.cpp
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -89,6 +89,17 @@
// Should print -22 (BAD_VALUE) and the device runtime shouldn't restart
printf("createInvalidDirectChannel=%d\n", ret);
+
+ // Secondary test: correct channel creation & destruction (should print 0)
+ ret = mgr.createDirectChannel(kMemSize, ASENSOR_DIRECT_CHANNEL_TYPE_HARDWARE_BUFFER,
+ resourceHandle);
+ printf("createValidDirectChannel=%d\n", ret);
+
+ // Third test: double-destroy (should not crash)
+ mgr.destroyDirectChannel(ret);
+ AHardwareBuffer_release(hardwareBuffer);
+ printf("duplicate destroyDirectChannel...\n");
+ mgr.destroyDirectChannel(ret);
}
int main() {
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 47bd91e..701071b 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -3947,7 +3947,7 @@
}
if (display) {
- const Fps refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
+ const Fps refreshRate = display->refreshRateConfigs().getActiveModePtr()->getFps();
const std::optional<Fps> renderRate =
mFlinger->mScheduler->getFrameRateOverride(getOwnerUid());
diff --git a/services/surfaceflinger/Scheduler/DispSyncSource.cpp b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
index 747032b..4af1f5c 100644
--- a/services/surfaceflinger/Scheduler/DispSyncSource.cpp
+++ b/services/surfaceflinger/Scheduler/DispSyncSource.cpp
@@ -188,10 +188,10 @@
VSyncSource::VSyncData DispSyncSource::getLatestVSyncData() const {
std::lock_guard lock(mVsyncMutex);
- nsecs_t expectedPresentTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
+ nsecs_t expectedPresentationTime = mVSyncTracker.nextAnticipatedVSyncTimeFrom(
systemTime() + mWorkDuration.get().count() + mReadyDuration.count());
- nsecs_t deadline = expectedPresentTime - mWorkDuration.get().count() - mReadyDuration.count();
- return {expectedPresentTime, deadline};
+ nsecs_t deadline = expectedPresentationTime - mReadyDuration.count();
+ return {expectedPresentationTime, deadline};
}
void DispSyncSource::dump(std::string& result) const {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index a48c921..d270655 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -27,6 +27,7 @@
#include <android-base/properties.h>
#include <android-base/stringprintf.h>
#include <ftl/enum.h>
+#include <ftl/fake_guard.h>
#include <utils/Trace.h>
#include "../SurfaceFlingerProperties.h"
@@ -325,6 +326,8 @@
const Policy* policy = getCurrentPolicyLocked();
const auto& defaultMode = mDisplayModes.get(policy->defaultMode)->get();
+ const auto& activeMode = *getActiveModeItLocked()->second;
+
// If the default mode group is different from the group of current mode,
// this means a layer requesting a seamed mode switch just disappeared and
// we should switch back to the default group.
@@ -332,7 +335,7 @@
// of the current mode, in order to prevent unnecessary seamed mode switches
// (e.g. when pausing a video playback).
const auto anchorGroup =
- seamedFocusedLayers > 0 ? mActiveModeIt->second->getGroup() : defaultMode->getGroup();
+ seamedFocusedLayers > 0 ? activeMode.getGroup() : defaultMode->getGroup();
// Consider the touch event if there are no Explicit* layers. Otherwise wait until after we've
// selected a refresh rate to see if we should apply touch boost.
@@ -387,12 +390,12 @@
for (auto& [modeIt, overallScore, fixedRateBelowThresholdLayersScore] : scores) {
const auto& [id, mode] = *modeIt;
- const bool isSeamlessSwitch = mode->getGroup() == mActiveModeIt->second->getGroup();
+ const bool isSeamlessSwitch = mode->getGroup() == activeMode.getGroup();
if (layer.seamlessness == Seamlessness::OnlySeamless && !isSeamlessSwitch) {
ALOGV("%s ignores %s to avoid non-seamless switch. Current mode = %s",
formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(),
- to_string(*mActiveModeIt->second).c_str());
+ to_string(activeMode).c_str());
continue;
}
@@ -401,7 +404,7 @@
ALOGV("%s ignores %s because it's not focused and the switch is going to be seamed."
" Current mode = %s",
formatLayerInfo(layer, weight).c_str(), to_string(*mode).c_str(),
- to_string(*mActiveModeIt->second).c_str());
+ to_string(activeMode).c_str());
continue;
}
@@ -413,7 +416,7 @@
const bool isInPolicyForDefault = mode->getGroup() == anchorGroup;
if (layer.seamlessness == Seamlessness::Default && !isInPolicyForDefault) {
ALOGV("%s ignores %s. Current mode = %s", formatLayerInfo(layer, weight).c_str(),
- to_string(*mode).c_str(), to_string(*mActiveModeIt->second).c_str());
+ to_string(*mode).c_str(), to_string(activeMode).c_str());
continue;
}
@@ -676,7 +679,7 @@
const DisplayModePtr& current = desiredActiveModeId
? mDisplayModes.get(*desiredActiveModeId)->get()
- : mActiveModeIt->second;
+ : getActiveModeItLocked()->second;
const DisplayModePtr& min = mMinRefreshRateModeIt->second;
if (current == min) {
@@ -688,16 +691,17 @@
}
const DisplayModePtr& RefreshRateConfigs::getMinRefreshRateByPolicyLocked() const {
+ const auto& activeMode = *getActiveModeItLocked()->second;
+
for (const DisplayModeIterator modeIt : mPrimaryRefreshRates) {
const auto& mode = modeIt->second;
- if (mActiveModeIt->second->getGroup() == mode->getGroup()) {
+ if (activeMode.getGroup() == mode->getGroup()) {
return mode;
}
}
- ALOGE("Can't find min refresh rate by policy with the same mode group"
- " as the current mode %s",
- to_string(*mActiveModeIt->second).c_str());
+ ALOGE("Can't find min refresh rate by policy with the same mode group as the current mode %s",
+ to_string(activeMode).c_str());
// Default to the lowest refresh rate.
return mPrimaryRefreshRates.front()->second;
@@ -708,6 +712,11 @@
return getMaxRefreshRateByPolicyLocked();
}
+const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked() const {
+ const int anchorGroup = getActiveModeItLocked()->second->getGroup();
+ return getMaxRefreshRateByPolicyLocked(anchorGroup);
+}
+
const DisplayModePtr& RefreshRateConfigs::getMaxRefreshRateByPolicyLocked(int anchorGroup) const {
for (auto it = mPrimaryRefreshRates.rbegin(); it != mPrimaryRefreshRates.rend(); ++it) {
const auto& mode = (*it)->second;
@@ -716,17 +725,28 @@
}
}
- ALOGE("Can't find max refresh rate by policy with the same mode group"
- " as the current mode %s",
- to_string(*mActiveModeIt->second).c_str());
+ const auto& activeMode = *getActiveModeItLocked()->second;
+ ALOGE("Can't find max refresh rate by policy with the same mode group as the current mode %s",
+ to_string(activeMode).c_str());
// Default to the highest refresh rate.
return mPrimaryRefreshRates.back()->second;
}
-DisplayModePtr RefreshRateConfigs::getActiveMode() const {
+DisplayModePtr RefreshRateConfigs::getActiveModePtr() const {
std::lock_guard lock(mLock);
- return mActiveModeIt->second;
+ return getActiveModeItLocked()->second;
+}
+
+const DisplayMode& RefreshRateConfigs::getActiveMode() const {
+ // Reads from kMainThreadContext do not require mLock.
+ ftl::FakeGuard guard(mLock);
+ return *mActiveModeIt->second;
+}
+
+DisplayModeIterator RefreshRateConfigs::getActiveModeItLocked() const {
+ // Reads under mLock do not require kMainThreadContext.
+ return FTL_FAKE_GUARD(kMainThreadContext, mActiveModeIt);
}
void RefreshRateConfigs::setActiveModeId(DisplayModeId modeId) {
@@ -744,7 +764,7 @@
Config config)
: mKnownFrameRates(constructKnownFrameRates(modes)), mConfig(config) {
initializeIdleTimer();
- updateDisplayModes(std::move(modes), activeModeId);
+ FTL_FAKE_GUARD(kMainThreadContext, updateDisplayModes(std::move(modes), activeModeId));
}
void RefreshRateConfigs::initializeIdleTimer() {
@@ -976,7 +996,7 @@
std::lock_guard lock(mLock);
- const auto activeModeId = mActiveModeIt->first;
+ const auto activeModeId = getActiveModeItLocked()->first;
result += " activeModeId="s;
result += std::to_string(activeModeId.value());
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index a79002e..b2cfb03 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -31,6 +31,7 @@
#include "DisplayHardware/HWComposer.h"
#include "Scheduler/OneShotTimer.h"
#include "Scheduler/StrongTyping.h"
+#include "ThreadContext.h"
namespace android::scheduler {
@@ -207,8 +208,11 @@
// uses the primary range, not the app request range.
DisplayModePtr getMaxRefreshRateByPolicy() const EXCLUDES(mLock);
- void setActiveModeId(DisplayModeId) EXCLUDES(mLock);
- DisplayModePtr getActiveMode() const EXCLUDES(mLock);
+ void setActiveModeId(DisplayModeId) EXCLUDES(mLock) REQUIRES(kMainThreadContext);
+
+ // See mActiveModeIt for thread safety.
+ DisplayModePtr getActiveModePtr() const EXCLUDES(mLock);
+ const DisplayMode& getActiveMode() const REQUIRES(kMainThreadContext);
// Returns a known frame rate that is the closest to frameRate
Fps findClosestKnownFrameRate(Fps frameRate) const;
@@ -332,6 +336,9 @@
void constructAvailableRefreshRates() REQUIRES(mLock);
+ // See mActiveModeIt for thread safety.
+ DisplayModeIterator getActiveModeItLocked() const REQUIRES(mLock);
+
std::pair<DisplayModePtr, GlobalSignals> getBestRefreshRateLocked(
const std::vector<LayerRequirement>&, GlobalSignals) const REQUIRES(mLock);
@@ -345,10 +352,8 @@
// Returns the highest refresh rate according to the current policy. May change at runtime. Only
// uses the primary range, not the app request range.
+ const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock);
const DisplayModePtr& getMaxRefreshRateByPolicyLocked(int anchorGroup) const REQUIRES(mLock);
- const DisplayModePtr& getMaxRefreshRateByPolicyLocked() const REQUIRES(mLock) {
- return getMaxRefreshRateByPolicyLocked(mActiveModeIt->second->getGroup());
- }
const Policy* getCurrentPolicyLocked() const REQUIRES(mLock);
bool isPolicyValidLocked(const Policy& policy) const REQUIRES(mLock);
@@ -361,7 +366,8 @@
float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&, Fps refreshRate) const
REQUIRES(mLock);
- void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock);
+ void updateDisplayModes(DisplayModes, DisplayModeId activeModeId) EXCLUDES(mLock)
+ REQUIRES(kMainThreadContext);
void initializeIdleTimer();
@@ -377,7 +383,10 @@
// is also dependent, so must be reset as well.
DisplayModes mDisplayModes GUARDED_BY(mLock);
- DisplayModeIterator mActiveModeIt GUARDED_BY(mLock);
+ // Written under mLock exclusively from kMainThreadContext, so reads from kMainThreadContext
+ // need not be under mLock.
+ DisplayModeIterator mActiveModeIt GUARDED_BY(mLock) GUARDED_BY(kMainThreadContext);
+
DisplayModeIterator mMinRefreshRateModeIt GUARDED_BY(mLock);
DisplayModeIterator mMaxRefreshRateModeIt GUARDED_BY(mLock);
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 55ae013..bec39a7 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -182,7 +182,7 @@
impl::EventThread::GetVsyncPeriodFunction Scheduler::makeGetVsyncPeriodFunction() const {
return [this](uid_t uid) {
- const Fps refreshRate = holdRefreshRateConfigs()->getActiveMode()->getFps();
+ const Fps refreshRate = holdRefreshRateConfigs()->getActiveModePtr()->getFps();
const nsecs_t currentPeriod = mVsyncSchedule->period().ns() ?: refreshRate.getPeriodNsecs();
const auto frameRate = getFrameRateOverride(uid);
@@ -320,7 +320,7 @@
// mode change is in progress. In that case we shouldn't dispatch an event
// as it will be dispatched when the current mode changes.
if (std::scoped_lock lock(mRefreshRateConfigsLock);
- mRefreshRateConfigs->getActiveMode() != mPolicy.mode) {
+ mRefreshRateConfigs->getActiveModePtr() != mPolicy.mode) {
return;
}
@@ -453,7 +453,7 @@
if (now - last > kIgnoreDelay) {
const auto refreshRate = [&] {
std::scoped_lock lock(mRefreshRateConfigsLock);
- return mRefreshRateConfigs->getActiveMode()->getFps();
+ return mRefreshRateConfigs->getActiveModePtr()->getFps();
}();
resyncToHardwareVsync(false, refreshRate);
}
@@ -577,7 +577,7 @@
// magic number
const Fps refreshRate = [&] {
std::scoped_lock lock(mRefreshRateConfigsLock);
- return mRefreshRateConfigs->getActiveMode()->getFps();
+ return mRefreshRateConfigs->getActiveModePtr()->getFps();
}();
constexpr Fps FPS_THRESHOLD_FOR_KERNEL_TIMER = 65_Hz;
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index eb3856d..afb3459 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -229,7 +229,7 @@
nsecs_t getVsyncPeriodFromRefreshRateConfigs() const EXCLUDES(mRefreshRateConfigsLock) {
std::scoped_lock lock(mRefreshRateConfigsLock);
- return mRefreshRateConfigs->getActiveMode()->getFps().getPeriodNsecs();
+ return mRefreshRateConfigs->getActiveModePtr()->getFps().getPeriodNsecs();
}
// Returns the framerate of the layer with the given sequence ID
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ca578e1..78eaa14 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1157,9 +1157,7 @@
return;
}
- const auto upcomingModeInfo =
- FTL_FAKE_GUARD(kMainThreadContext, display->getUpcomingActiveMode());
-
+ const auto upcomingModeInfo = display->getUpcomingActiveMode();
if (!upcomingModeInfo.mode) {
// There is no pending mode change. This can happen if the active
// display changed and the mode change happened on a different display.
@@ -1273,9 +1271,8 @@
constraints.seamlessRequired = false;
hal::VsyncPeriodChangeTimeline outTimeline;
- const auto status = FTL_FAKE_GUARD(kMainThreadContext,
- display->initiateModeChange(*desiredActiveMode,
- constraints, &outTimeline));
+ const auto status =
+ display->initiateModeChange(*desiredActiveMode, constraints, &outTimeline);
if (status != NO_ERROR) {
// initiateModeChange may fail if a hotplug event is just about
@@ -2161,7 +2158,7 @@
// Hold mStateLock as chooseRefreshRateForContent promotes wp<Layer> to sp<Layer>
// and may eventually call to ~Layer() if it holds the last reference
{
- Mutex::Autolock _l(mStateLock);
+ Mutex::Autolock lock(mStateLock);
mScheduler->chooseRefreshRateForContent();
setActiveModeInHwcIfNeeded();
}
@@ -3060,9 +3057,10 @@
}
}
}
+
void SurfaceFlinger::updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay) {
mVsyncConfiguration->reset();
- const Fps refreshRate = activeDisplay->refreshRateConfigs().getActiveMode()->getFps();
+ const Fps refreshRate = activeDisplay->refreshRateConfigs().getActiveMode().getFps();
updatePhaseConfiguration(refreshRate);
mRefreshRateStats->setRefreshRate(refreshRate);
}
@@ -4724,8 +4722,6 @@
}
}
-// ---------------------------------------------------------------------------
-
void SurfaceFlinger::onInitializeDisplays() {
const auto display = getDefaultDisplayDeviceLocked();
if (!display) return;
@@ -4763,8 +4759,9 @@
void SurfaceFlinger::initializeDisplays() {
// Async since we may be called from the main thread.
- static_cast<void>(
- mScheduler->schedule([this]() FTL_FAKE_GUARD(mStateLock) { onInitializeDisplays(); }));
+ static_cast<void>(mScheduler->schedule(
+ [this]() FTL_FAKE_GUARD(mStateLock)
+ FTL_FAKE_GUARD(kMainThreadContext) { onInitializeDisplays(); }));
}
void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode) {
@@ -4796,7 +4793,7 @@
if (mInterceptor->isEnabled()) {
mInterceptor->savePowerModeUpdate(display->getSequenceId(), static_cast<int32_t>(mode));
}
- const auto refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
+ const auto refreshRate = display->refreshRateConfigs().getActiveMode().getFps();
if (*currentMode == hal::PowerMode::OFF) {
// Turn on the display
if (isInternalDisplay && (!activeDisplay || !activeDisplay->isPoweredOn())) {
@@ -4870,7 +4867,8 @@
}
void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
- auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) {
+ auto future = mScheduler->schedule([=]() FTL_FAKE_GUARD(mStateLock) FTL_FAKE_GUARD(
+ kMainThreadContext) {
const auto display = getDisplayDeviceLocked(displayToken);
if (!display) {
ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
@@ -7021,7 +7019,7 @@
refreshRate = *frameRateOverride;
} else if (!getHwComposer().isHeadless()) {
if (const auto display = FTL_FAKE_GUARD(mStateLock, getDefaultDisplayDeviceLocked())) {
- refreshRate = display->refreshRateConfigs().getActiveMode()->getFps();
+ refreshRate = display->refreshRateConfigs().getActiveModePtr()->getFps();
}
}
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 2af17e7..f7684a0 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -648,22 +648,20 @@
// Show spinner with refresh rate overlay
bool mRefreshRateOverlaySpinner = false;
- // Called on the main thread in response to initializeDisplays()
- void onInitializeDisplays() REQUIRES(mStateLock);
// Sets the desired active mode bit. It obtains the lock, and sets mDesiredActiveMode.
void setDesiredActiveMode(const ActiveModeInfo& info) REQUIRES(mStateLock);
status_t setActiveModeFromBackdoor(const sp<display::DisplayToken>&, DisplayModeId);
// Sets the active mode and a new refresh rate in SF.
- void updateInternalStateWithChangedMode() REQUIRES(mStateLock);
+ void updateInternalStateWithChangedMode() REQUIRES(mStateLock, kMainThreadContext);
// Calls to setActiveMode on the main thread if there is a pending mode change
// that needs to be applied.
- void setActiveModeInHwcIfNeeded() REQUIRES(mStateLock);
+ void setActiveModeInHwcIfNeeded() REQUIRES(mStateLock, kMainThreadContext);
void clearDesiredActiveModeState(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called when active mode is no longer is progress
void desiredActiveModeChangeDone(const sp<DisplayDevice>&) REQUIRES(mStateLock);
// Called on the main thread in response to setPowerMode()
void setPowerModeInternal(const sp<DisplayDevice>& display, hal::PowerMode mode)
- REQUIRES(mStateLock);
+ REQUIRES(mStateLock, kMainThreadContext);
// Returns true if the display has a visible HDR layer in its layer stack.
bool hasVisibleHdrLayer(const sp<DisplayDevice>& display) REQUIRES(mStateLock);
@@ -680,8 +678,9 @@
const std::optional<scheduler::RefreshRateConfigs::Policy>& policy, bool overridePolicy)
EXCLUDES(mStateLock);
- void commitTransactions() EXCLUDES(mStateLock);
- void commitTransactionsLocked(uint32_t transactionFlags) REQUIRES(mStateLock);
+ void commitTransactions() EXCLUDES(mStateLock) REQUIRES(kMainThreadContext);
+ void commitTransactionsLocked(uint32_t transactionFlags)
+ REQUIRES(mStateLock, kMainThreadContext);
void doCommitTransactions() REQUIRES(mStateLock);
// Returns whether a new buffer has been latched.
@@ -824,8 +823,10 @@
/*
* Display and layer stack management
*/
- // called when starting, or restarting after system_server death
+
+ // Called during boot, and restart after system_server death.
void initializeDisplays();
+ void onInitializeDisplays() REQUIRES(mStateLock, kMainThreadContext);
bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) {
return display->getDisplayToken() == mActiveDisplayToken;
@@ -957,11 +958,12 @@
const DisplayDeviceState& state,
const sp<compositionengine::DisplaySurface>& displaySurface,
const sp<IGraphicBufferProducer>& producer) REQUIRES(mStateLock);
- void processDisplayChangesLocked() REQUIRES(mStateLock);
+ void processDisplayChangesLocked() REQUIRES(mStateLock, kMainThreadContext);
void processDisplayRemoved(const wp<IBinder>& displayToken) REQUIRES(mStateLock);
void processDisplayChanged(const wp<IBinder>& displayToken,
const DisplayDeviceState& currentState,
- const DisplayDeviceState& drawingState) REQUIRES(mStateLock);
+ const DisplayDeviceState& drawingState)
+ REQUIRES(mStateLock, kMainThreadContext);
void dispatchDisplayHotplugEvent(PhysicalDisplayId displayId, bool connected);
@@ -1022,7 +1024,8 @@
VirtualDisplayId acquireVirtualDisplay(ui::Size, ui::PixelFormat) REQUIRES(mStateLock);
void releaseVirtualDisplay(VirtualDisplayId);
- void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay) REQUIRES(mStateLock);
+ void onActiveDisplayChangedLocked(const sp<DisplayDevice>& activeDisplay)
+ REQUIRES(mStateLock, kMainThreadContext);
void onActiveDisplaySizeChanged(const sp<DisplayDevice>& activeDisplay);
@@ -1096,7 +1099,7 @@
int getMaxAcquiredBufferCountForRefreshRate(Fps refreshRate) const;
void updateInternalDisplayVsyncLocked(const sp<DisplayDevice>& activeDisplay)
- REQUIRES(mStateLock);
+ REQUIRES(mStateLock, kMainThreadContext);
bool isHdrLayer(Layer* layer) const;
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
index 28b875a..79112bd 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzer.cpp
@@ -237,7 +237,8 @@
mTestableFlinger.enableHalVirtualDisplays(mFdp.ConsumeBool());
- mTestableFlinger.commitTransactionsLocked(mFdp.ConsumeIntegral<uint32_t>());
+ FTL_FAKE_GUARD(kMainThreadContext,
+ mTestableFlinger.commitTransactionsLocked(mFdp.ConsumeIntegral<uint32_t>()));
mTestableFlinger.notifyPowerBoost(mFdp.ConsumeIntegral<int32_t>());
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
index 3aa3633..a861263 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_fuzzers_utils.h
@@ -600,14 +600,18 @@
mFlinger->binderDied(display);
mFlinger->onFirstRef();
- mFlinger->commitTransactions();
mFlinger->updateInputFlinger();
mFlinger->updateCursorAsync();
setVsyncConfig(&mFdp);
- FTL_FAKE_GUARD(kMainThreadContext,
- mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp)));
+ {
+ ftl::FakeGuard guard(kMainThreadContext);
+
+ mFlinger->commitTransactions();
+ mFlinger->flushTransactionQueues(getFuzzedVsyncId(mFdp));
+ mFlinger->postComposition();
+ }
mFlinger->setTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
mFlinger->clearTransactionFlags(mFdp.ConsumeIntegral<uint32_t>());
@@ -624,8 +628,6 @@
mFlinger->getMaxAcquiredBufferCountForCurrentRefreshRate(mFdp.ConsumeIntegral<uid_t>());
- FTL_FAKE_GUARD(kMainThreadContext, mFlinger->postComposition());
-
mFlinger->calculateExpectedPresentTime({});
mFlinger->enableHalVirtualDisplays(mFdp.ConsumeBool());
@@ -664,7 +666,8 @@
}
mRefreshRateConfigs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60);
- const auto fps = mRefreshRateConfigs->getActiveMode()->getFps();
+ const auto fps =
+ FTL_FAKE_GUARD(kMainThreadContext, mRefreshRateConfigs->getActiveMode().getFps());
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps);
mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
mFlinger->mVsyncConfiguration->getCurrentConfigs());
@@ -715,9 +718,9 @@
void enableHalVirtualDisplays(bool enable) { mFlinger->enableHalVirtualDisplays(enable); }
- auto commitTransactionsLocked(uint32_t transactionFlags) {
+ void commitTransactionsLocked(uint32_t transactionFlags) FTL_FAKE_GUARD(kMainThreadContext) {
Mutex::Autolock lock(mFlinger->mStateLock);
- return mFlinger->commitTransactionsLocked(transactionFlags);
+ mFlinger->commitTransactionsLocked(transactionFlags);
}
auto setDisplayStateLocked(const DisplayState &s) {
diff --git a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
index 9584492..3fc2b7e 100644
--- a/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
+++ b/services/surfaceflinger/fuzzer/surfaceflinger_scheduler_fuzzer.cpp
@@ -366,7 +366,7 @@
{modeId,
{Fps::fromValue(mFdp.ConsumeFloatingPoint<float>()),
Fps::fromValue(mFdp.ConsumeFloatingPoint<float>())}});
- refreshRateConfigs.setActiveModeId(modeId);
+ FTL_FAKE_GUARD(kMainThreadContext, refreshRateConfigs.setActiveModeId(modeId));
RefreshRateConfigs::isFractionalPairOrMultiple(Fps::fromValue(
mFdp.ConsumeFloatingPoint<float>()),
diff --git a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
index ec27eda..67ace1a 100644
--- a/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DispSyncSourceTest.cpp
@@ -292,9 +292,10 @@
TEST_F(DispSyncSourceTest, getLatestVsyncData) {
const nsecs_t now = systemTime();
- const nsecs_t vsyncInternalDuration = mWorkDuration.count() + mReadyDuration.count();
+ const nsecs_t expectedPresentationTime =
+ now + mWorkDuration.count() + mReadyDuration.count() + 1;
EXPECT_CALL(*mVSyncTracker, nextAnticipatedVSyncTimeFrom(_))
- .WillOnce(Return(now + vsyncInternalDuration + 1));
+ .WillOnce(Return(expectedPresentationTime));
{
InSequence seq;
EXPECT_CALL(*mVSyncDispatch, registerCallback(_, mName)).Times(1);
@@ -306,10 +307,8 @@
EXPECT_TRUE(mDispSyncSource);
const auto vsyncData = mDispSyncSource->getLatestVSyncData();
- ASSERT_GT(vsyncData.deadlineTimestamp, now);
- ASSERT_GT(vsyncData.expectedPresentationTime, vsyncData.deadlineTimestamp);
- EXPECT_EQ(vsyncData.deadlineTimestamp,
- vsyncData.expectedPresentationTime - vsyncInternalDuration);
+ ASSERT_EQ(vsyncData.expectedPresentationTime, expectedPresentationTime);
+ EXPECT_EQ(vsyncData.deadlineTimestamp, expectedPresentationTime - mReadyDuration.count());
}
} // namespace
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 188fd58..4f20932 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -18,6 +18,7 @@
#define LOG_TAG "SchedulerUnittests"
#include <ftl/enum.h>
+#include <ftl/fake_guard.h>
#include <gmock/gmock.h>
#include <log/log.h>
#include <ui/Size.h>
@@ -41,6 +42,16 @@
struct TestableRefreshRateConfigs : RefreshRateConfigs {
using RefreshRateConfigs::RefreshRateConfigs;
+ void setActiveModeId(DisplayModeId modeId) {
+ ftl::FakeGuard guard(kMainThreadContext);
+ return RefreshRateConfigs::setActiveModeId(modeId);
+ }
+
+ const DisplayMode& getActiveMode() const {
+ ftl::FakeGuard guard(kMainThreadContext);
+ return RefreshRateConfigs::getActiveMode();
+ }
+
DisplayModePtr getMinSupportedRefreshRate() const {
std::lock_guard lock(mLock);
return mMinRefreshRateModeIt->second;
@@ -243,20 +254,20 @@
TEST_F(RefreshRateConfigsTest, twoModes_getActiveMode) {
TestableRefreshRateConfigs configs(kModes_60_90, kModeId60);
{
- const auto mode = configs.getActiveMode();
- EXPECT_EQ(mode->getId(), kModeId60);
+ const auto& mode = configs.getActiveMode();
+ EXPECT_EQ(mode.getId(), kModeId60);
}
configs.setActiveModeId(kModeId90);
{
- const auto mode = configs.getActiveMode();
- EXPECT_EQ(mode->getId(), kModeId90);
+ const auto& mode = configs.getActiveMode();
+ EXPECT_EQ(mode.getId(), kModeId90);
}
EXPECT_GE(configs.setDisplayManagerPolicy({kModeId90, {90_Hz, 90_Hz}}), 0);
{
- const auto mode = configs.getActiveMode();
- EXPECT_EQ(mode->getId(), kModeId90);
+ const auto& mode = configs.getActiveMode();
+ EXPECT_EQ(mode.getId(), kModeId90);
}
}
@@ -1898,30 +1909,30 @@
}
TEST_F(RefreshRateConfigsTest, getFrameRateDivisor) {
- RefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30);
+ TestableRefreshRateConfigs configs(kModes_30_60_72_90_120, kModeId30);
const auto frameRate = 30_Hz;
- Fps displayRefreshRate = configs.getActiveMode()->getFps();
+ Fps displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(1, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setActiveModeId(kModeId60);
- displayRefreshRate = configs.getActiveMode()->getFps();
+ displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(2, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setActiveModeId(kModeId72);
- displayRefreshRate = configs.getActiveMode()->getFps();
+ displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setActiveModeId(kModeId90);
- displayRefreshRate = configs.getActiveMode()->getFps();
+ displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(3, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setActiveModeId(kModeId120);
- displayRefreshRate = configs.getActiveMode()->getFps();
+ displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, frameRate));
configs.setActiveModeId(kModeId90);
- displayRefreshRate = configs.getActiveMode()->getFps();
+ displayRefreshRate = configs.getActiveMode().getFps();
EXPECT_EQ(4, RefreshRateConfigs::getFrameRateDivisor(displayRefreshRate, 22.5_Hz));
EXPECT_EQ(0, RefreshRateConfigs::getFrameRateDivisor(24_Hz, 25_Hz));
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index a6b3f7c..f8fdb65 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -223,7 +223,7 @@
configs = std::make_shared<scheduler::RefreshRateConfigs>(modes, kModeId60);
}
- const auto fps = configs->getActiveMode()->getFps();
+ const auto fps = FTL_FAKE_GUARD(kMainThreadContext, configs->getActiveMode().getFps());
mFlinger->mVsyncConfiguration = mFactory.createVsyncConfiguration(fps);
mFlinger->mVsyncModulator = sp<scheduler::VsyncModulator>::make(
mFlinger->mVsyncConfiguration->getCurrentConfigs());
@@ -371,6 +371,7 @@
void commitTransactionsLocked(uint32_t transactionFlags) {
Mutex::Autolock lock(mFlinger->mStateLock);
+ ftl::FakeGuard guard(kMainThreadContext);
mFlinger->commitTransactionsLocked(transactionFlags);
}
@@ -464,6 +465,7 @@
void onActiveDisplayChanged(const sp<DisplayDevice>& activeDisplay) {
Mutex::Autolock lock(mFlinger->mStateLock);
+ ftl::FakeGuard guard(kMainThreadContext);
mFlinger->onActiveDisplayChangedLocked(activeDisplay);
}