summaryrefslogtreecommitdiff
path: root/include/input/InputTransport.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/input/InputTransport.h')
-rw-r--r--include/input/InputTransport.h221
1 files changed, 166 insertions, 55 deletions
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 7ca9031f77..360dfbfd73 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -30,18 +30,22 @@
*/
#include <string>
+#include <unordered_map>
#include <android-base/chrono_utils.h>
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
#include <binder/IBinder.h>
+#include <binder/Parcelable.h>
#include <input/Input.h>
+#include <sys/stat.h>
+#include <ui/Transform.h>
#include <utils/BitSet.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
#include <utils/Timers.h>
-#include <utils/Vector.h>
-#include <android-base/unique_fd.h>
namespace android {
class Parcel;
@@ -65,24 +69,29 @@ struct InputMessage {
MOTION,
FINISHED,
FOCUS,
+ CAPTURE,
+ DRAG,
+ TIMELINE,
};
struct Header {
Type type; // 4 bytes
- // We don't need this field in order to align the body below but we
- // leave it here because InputMessage::size() and other functions
- // compute the size of this structure as sizeof(Header) + sizeof(Body).
- uint32_t padding;
+ uint32_t seq;
} header;
- // Body *must* be 8 byte aligned.
// For keys and motions, rely on the fact that std::array takes up exactly as much space
// as the underlying data. This is not guaranteed by C++, but it simplifies the conversions.
static_assert(sizeof(std::array<uint8_t, 32>) == 32);
+
+ // For bool values, rely on the fact that they take up exactly one byte. This is not guaranteed
+ // by C++ and is implementation-dependent, but it simplifies the conversions.
+ static_assert(sizeof(bool) == 1);
+
+ // Body *must* be 8 byte aligned.
union Body {
struct Key {
- uint32_t seq;
int32_t eventId;
+ uint32_t empty1;
nsecs_t eventTime __attribute__((aligned(8)));
int32_t deviceId;
int32_t source;
@@ -101,8 +110,8 @@ struct InputMessage {
} key;
struct Motion {
- uint32_t seq;
int32_t eventId;
+ uint32_t empty1;
nsecs_t eventTime __attribute__((aligned(8)));
int32_t deviceId;
int32_t source;
@@ -117,14 +126,18 @@ struct InputMessage {
uint8_t empty2[3]; // 3 bytes to fill gap created by classification
int32_t edgeFlags;
nsecs_t downTime __attribute__((aligned(8)));
- float xScale;
- float yScale;
- float xOffset;
- float yOffset;
+ float dsdx;
+ float dtdx;
+ float dtdy;
+ float dsdy;
+ float tx;
+ float ty;
float xPrecision;
float yPrecision;
float xCursorPosition;
float yCursorPosition;
+ int32_t displayWidth;
+ int32_t displayHeight;
uint32_t pointerCount;
uint32_t empty3;
/**
@@ -151,22 +164,48 @@ struct InputMessage {
} motion;
struct Finished {
- uint32_t seq;
- uint32_t handled; // actually a bool, but we must maintain 8-byte alignment
+ bool handled;
+ uint8_t empty[7];
+ nsecs_t consumeTime; // The time when the event was consumed by the receiving end
inline size_t size() const { return sizeof(Finished); }
} finished;
struct Focus {
- uint32_t seq;
int32_t eventId;
- uint32_t empty1;
- // The following two fields take up 4 bytes total
- uint16_t hasFocus; // actually a bool
- uint16_t inTouchMode; // actually a bool, but we must maintain 8-byte alignment
+ // The following 3 fields take up 4 bytes total
+ bool hasFocus;
+ bool inTouchMode;
+ uint8_t empty[2];
inline size_t size() const { return sizeof(Focus); }
} focus;
+
+ struct Capture {
+ int32_t eventId;
+ bool pointerCaptureEnabled;
+ uint8_t empty[3];
+
+ inline size_t size() const { return sizeof(Capture); }
+ } capture;
+
+ struct Drag {
+ int32_t eventId;
+ float x;
+ float y;
+ bool isExiting;
+ uint8_t empty[3];
+
+ inline size_t size() const { return sizeof(Drag); }
+ } drag;
+
+ struct Timeline {
+ int32_t eventId;
+ uint32_t empty;
+ std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
+
+ inline size_t size() const { return sizeof(Timeline); }
+ } timeline;
} __attribute__((aligned(8))) body;
bool isValid(size_t actualSize) const;
@@ -182,14 +221,15 @@ struct InputMessage {
*
* The input channel is closed when all references to it are released.
*/
-class InputChannel : public RefBase {
-protected:
- virtual ~InputChannel();
-
+class InputChannel : public Parcelable {
public:
- static sp<InputChannel> create(const std::string& name, android::base::unique_fd fd,
- sp<IBinder> token);
-
+ static std::unique_ptr<InputChannel> create(const std::string& name,
+ android::base::unique_fd fd, sp<IBinder> token);
+ InputChannel() = default;
+ InputChannel(const InputChannel& other)
+ : mName(other.mName), mFd(::dup(other.mFd)), mToken(other.mToken){};
+ InputChannel(const std::string name, android::base::unique_fd fd, sp<IBinder> token);
+ ~InputChannel() override;
/**
* Create a pair of input channels.
* The two returned input channels are equivalent, and are labeled as "server" and "client"
@@ -198,10 +238,12 @@ public:
* Return OK on success.
*/
static status_t openInputChannelPair(const std::string& name,
- sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
+ std::unique_ptr<InputChannel>& outServerChannel,
+ std::unique_ptr<InputChannel>& outClientChannel);
inline std::string getName() const { return mName; }
- inline int getFd() const { return mFd.get(); }
+ inline const android::base::unique_fd& getFd() const { return mFd; }
+ inline sp<IBinder> getToken() const { return mToken; }
/* Send a message to the other endpoint.
*
@@ -229,10 +271,12 @@ public:
status_t receiveMessage(InputMessage* msg);
/* Return a new object that has a duplicate of this channel's fd. */
- sp<InputChannel> dup() const;
+ std::unique_ptr<InputChannel> dup() const;
+
+ void copyTo(InputChannel& outChannel) const;
- status_t write(Parcel& out) const;
- static sp<InputChannel> read(const Parcel& from);
+ status_t readFromParcel(const android::Parcel* parcel) override;
+ status_t writeToParcel(android::Parcel* parcel) const override;
/**
* The connection token is used to identify the input connection, i.e.
@@ -248,8 +292,22 @@ public:
*/
sp<IBinder> getConnectionToken() const;
+ bool operator==(const InputChannel& inputChannel) const {
+ struct stat lhs, rhs;
+ if (fstat(mFd.get(), &lhs) != 0) {
+ return false;
+ }
+ if (fstat(inputChannel.getFd(), &rhs) != 0) {
+ return false;
+ }
+ // If file descriptors are pointing to same inode they are duplicated fds.
+ return inputChannel.getName() == getName() && inputChannel.getConnectionToken() == mToken &&
+ lhs.st_ino == rhs.st_ino;
+ }
+
private:
- InputChannel(const std::string& name, android::base::unique_fd fd, sp<IBinder> token);
+ base::unique_fd dupFd() const;
+
std::string mName;
android::base::unique_fd mFd;
@@ -262,13 +320,13 @@ private:
class InputPublisher {
public:
/* Creates a publisher associated with an input channel. */
- explicit InputPublisher(const sp<InputChannel>& channel);
+ explicit InputPublisher(const std::shared_ptr<InputChannel>& channel);
/* Destroys the publisher and releases its input channel. */
~InputPublisher();
/* Gets the underlying input channel. */
- inline sp<InputChannel> getChannel() { return mChannel; }
+ inline std::shared_ptr<InputChannel> getChannel() { return mChannel; }
/* Publishes a key event to the input channel.
*
@@ -295,10 +353,10 @@ public:
int32_t displayId, std::array<uint8_t, 32> hmac, int32_t action,
int32_t actionButton, int32_t flags, int32_t edgeFlags,
int32_t metaState, int32_t buttonState,
- MotionClassification classification, float xScale, float yScale,
- float xOffset, float yOffset, float xPrecision, float yPrecision,
- float xCursorPosition, float yCursorPosition, nsecs_t downTime,
- nsecs_t eventTime, uint32_t pointerCount,
+ MotionClassification classification, const ui::Transform& transform,
+ float xPrecision, float yPrecision, float xCursorPosition,
+ float yCursorPosition, int32_t displayWidth, int32_t displayHeight,
+ nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
const PointerProperties* pointerProperties,
const PointerCoords* pointerCoords);
@@ -311,22 +369,60 @@ public:
*/
status_t publishFocusEvent(uint32_t seq, int32_t eventId, bool hasFocus, bool inTouchMode);
- /* Receives the finished signal from the consumer in reply to the original dispatch signal.
- * If a signal was received, returns the message sequence number,
- * and whether the consumer handled the message.
+ /* Publishes a capture event to the input channel.
*
- * The returned sequence number is never 0 unless the operation failed.
+ * Returns OK on success.
+ * Returns WOULD_BLOCK if the channel is full.
+ * Returns DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
+ */
+ status_t publishCaptureEvent(uint32_t seq, int32_t eventId, bool pointerCaptureEnabled);
+
+ /* Publishes a drag event to the input channel.
*
* Returns OK on success.
- * Returns WOULD_BLOCK if there is no signal present.
+ * Returns WOULD_BLOCK if the channel is full.
* Returns DEAD_OBJECT if the channel's peer has been closed.
* Other errors probably indicate that the channel is broken.
*/
- status_t receiveFinishedSignal(uint32_t* outSeq, bool* outHandled);
+ status_t publishDragEvent(uint32_t seq, int32_t eventId, float x, float y, bool isExiting);
-private:
+ struct Finished {
+ uint32_t seq;
+ bool handled;
+ nsecs_t consumeTime;
+ };
+
+ struct Timeline {
+ int32_t inputEventId;
+ std::array<nsecs_t, GraphicsTimeline::SIZE> graphicsTimeline;
+ };
+
+ typedef std::variant<Finished, Timeline> ConsumerResponse;
+ /* Receive a signal from the consumer in reply to the original dispatch signal.
+ * If a signal was received, returns a Finished or a Timeline object.
+ * The InputConsumer should return a Finished object for every InputMessage that it is sent
+ * to confirm that it has been processed and that the InputConsumer is responsive.
+ * If several InputMessages are sent to InputConsumer, it's possible to receive Finished
+ * events out of order for those messages.
+ *
+ * The Timeline object is returned whenever the receiving end has processed a graphical frame
+ * and is returning the timeline of the frame. Not all input events will cause a Timeline
+ * object to be returned, and there is not guarantee about when it will arrive.
+ *
+ * If an object of Finished is returned, the returned sequence number is never 0 unless the
+ * operation failed.
+ *
+ * Returned error codes:
+ * OK on success.
+ * WOULD_BLOCK if there is no signal present.
+ * DEAD_OBJECT if the channel's peer has been closed.
+ * Other errors probably indicate that the channel is broken.
+ */
+ android::base::Result<ConsumerResponse> receiveConsumerResponse();
- sp<InputChannel> mChannel;
+private:
+ std::shared_ptr<InputChannel> mChannel;
};
/*
@@ -335,13 +431,13 @@ private:
class InputConsumer {
public:
/* Creates a consumer associated with an input channel. */
- explicit InputConsumer(const sp<InputChannel>& channel);
+ explicit InputConsumer(const std::shared_ptr<InputChannel>& channel);
/* Destroys the consumer and releases its input channel. */
~InputConsumer();
/* Gets the underlying input channel. */
- inline sp<InputChannel> getChannel() { return mChannel; }
+ inline std::shared_ptr<InputChannel> getChannel() { return mChannel; }
/* Consumes an input event from the input channel and copies its contents into
* an InputEvent object created using the specified factory.
@@ -379,6 +475,9 @@ public:
*/
status_t sendFinishedSignal(uint32_t seq, bool handled);
+ status_t sendTimeline(int32_t inputEventId,
+ std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
+
/* Returns true if there is a deferred event waiting.
*
* Should be called after calling consume() to determine whether the consumer
@@ -411,12 +510,13 @@ public:
*/
int32_t getPendingBatchSource() const;
+ std::string dump() const;
+
private:
// True if touch resampling is enabled.
const bool mResampleTouch;
- // The input channel.
- sp<InputChannel> mChannel;
+ std::shared_ptr<InputChannel> mChannel;
// The current input message.
InputMessage mMsg;
@@ -427,9 +527,9 @@ private:
// Batched motion events per device and source.
struct Batch {
- Vector<InputMessage> samples;
+ std::vector<InputMessage> samples;
};
- Vector<Batch> mBatches;
+ std::vector<Batch> mBatches;
// Touch state per device and source, only for sources of class pointer.
struct History {
@@ -516,7 +616,7 @@ private:
return false;
}
};
- Vector<TouchState> mTouchStates;
+ std::vector<TouchState> mTouchStates;
// Chain of batched sequence numbers. When multiple input messages are combined into
// a batch, we append a record here that associates the last sequence number in the
@@ -526,7 +626,14 @@ private:
uint32_t seq; // sequence number of batched input message
uint32_t chain; // sequence number of previous batched input message
};
- Vector<SeqChain> mSeqChains;
+ std::vector<SeqChain> mSeqChains;
+
+ // The time at which each event with the sequence number 'seq' was consumed.
+ // This data is provided in 'finishInputEvent' so that the receiving end can measure the latency
+ // This collection is populated when the event is received, and the entries are erased when the
+ // events are finished. It should not grow infinitely because if an event is not ack'd, ANR
+ // will be raised for that connection, and no further events will be posted to that channel.
+ std::unordered_map<uint32_t /*seq*/, nsecs_t /*consumeTime*/> mConsumeTimes;
status_t consumeBatch(InputEventFactoryInterface* factory,
nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
@@ -540,12 +647,16 @@ private:
ssize_t findBatch(int32_t deviceId, int32_t source) const;
ssize_t findTouchState(int32_t deviceId, int32_t source) const;
+ nsecs_t getConsumeTime(uint32_t seq) const;
+ void popConsumeTime(uint32_t seq);
status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
static void rewriteMessage(TouchState& state, InputMessage& msg);
static void initializeKeyEvent(KeyEvent* event, const InputMessage* msg);
static void initializeMotionEvent(MotionEvent* event, const InputMessage* msg);
static void initializeFocusEvent(FocusEvent* event, const InputMessage* msg);
+ static void initializeCaptureEvent(CaptureEvent* event, const InputMessage* msg);
+ static void initializeDragEvent(DragEvent* event, const InputMessage* msg);
static void addSample(MotionEvent* event, const InputMessage* msg);
static bool canAddSample(const Batch& batch, const InputMessage* msg);
static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);