• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 /*
20  * Native input transport.
21  *
22  * The InputConsumer is used by the application to receive events from the input dispatcher.
23  */
24 
25 #include "InputTransport.h"
26 
27 namespace android {
28 
29 /*
30  * Consumes input events from an input channel.
31  */
32 class InputConsumer {
33 public:
34     /* Create a consumer associated with an input channel. */
35     explicit InputConsumer(const std::shared_ptr<InputChannel>& channel);
36     /* Create a consumer associated with an input channel, override resampling system property */
37     explicit InputConsumer(const std::shared_ptr<InputChannel>& channel,
38                            bool enableTouchResampling);
39 
40     /* Destroys the consumer and releases its input channel. */
41     ~InputConsumer();
42 
43     /* Gets the underlying input channel. */
getChannel()44     inline std::shared_ptr<InputChannel> getChannel() { return mChannel; }
45 
46     /* Consumes an input event from the input channel and copies its contents into
47      * an InputEvent object created using the specified factory.
48      *
49      * Tries to combine a series of move events into larger batches whenever possible.
50      *
51      * If consumeBatches is false, then defers consuming pending batched events if it
52      * is possible for additional samples to be added to them later.  Call hasPendingBatch()
53      * to determine whether a pending batch is available to be consumed.
54      *
55      * If consumeBatches is true, then events are still batched but they are consumed
56      * immediately as soon as the input channel is exhausted.
57      *
58      * The frameTime parameter specifies the time when the current display frame started
59      * rendering in the CLOCK_MONOTONIC time base, or -1 if unknown.
60      *
61      * The returned sequence number is never 0 unless the operation failed.
62      *
63      * Returns OK on success.
64      * Returns WOULD_BLOCK if there is no event present.
65      * Returns DEAD_OBJECT if the channel's peer has been closed.
66      * Returns NO_MEMORY if the event could not be created.
67      * Other errors probably indicate that the channel is broken.
68      */
69     status_t consume(InputEventFactoryInterface* factory, bool consumeBatches, nsecs_t frameTime,
70                      uint32_t* outSeq, InputEvent** outEvent);
71 
72     /* Sends a finished signal to the publisher to inform it that the message
73      * with the specified sequence number has finished being process and whether
74      * the message was handled by the consumer.
75      *
76      * Returns OK on success.
77      * Returns BAD_VALUE if seq is 0.
78      * Other errors probably indicate that the channel is broken.
79      */
80     status_t sendFinishedSignal(uint32_t seq, bool handled);
81 
82     status_t sendTimeline(int32_t inputEventId,
83                           std::array<nsecs_t, GraphicsTimeline::SIZE> timeline);
84 
85     /* Returns true if there is a pending batch.
86      *
87      * Should be called after calling consume() with consumeBatches == false to determine
88      * whether consume() should be called again later on with consumeBatches == true.
89      */
90     bool hasPendingBatch() const;
91 
92     /* Returns the source of first pending batch if exist.
93      *
94      * Should be called after calling consume() with consumeBatches == false to determine
95      * whether consume() should be called again later on with consumeBatches == true.
96      */
97     int32_t getPendingBatchSource() const;
98 
99     /* Returns true when there is *likely* a pending batch or a pending event in the channel.
100      *
101      * This is only a performance hint and may return false negative results. Clients should not
102      * rely on availability of the message based on the return value.
103      */
104     bool probablyHasInput() const;
105 
106     std::string dump() const;
107 
108 private:
109     // True if touch resampling is enabled.
110     const bool mResampleTouch;
111 
112     std::shared_ptr<InputChannel> mChannel;
113 
114     // TODO(b/311142655): delete this temporary tracing after the ANR bug is fixed
115     const std::string mProcessingTraceTag;
116     const std::string mLifetimeTraceTag;
117     const int32_t mLifetimeTraceCookie;
118 
119     // The current input message.
120     InputMessage mMsg;
121 
122     // True if mMsg contains a valid input message that was deferred from the previous
123     // call to consume and that still needs to be handled.
124     bool mMsgDeferred;
125 
126     // Batched motion events per device and source.
127     struct Batch {
128         std::vector<InputMessage> samples;
129     };
130     std::vector<Batch> mBatches;
131 
132     // Touch state per device and source, only for sources of class pointer.
133     struct History {
134         nsecs_t eventTime;
135         BitSet32 idBits;
136         int32_t idToIndex[MAX_POINTER_ID + 1];
137         PointerCoords pointers[MAX_POINTERS];
138 
initializeFromHistory139         void initializeFrom(const InputMessage& msg) {
140             eventTime = msg.body.motion.eventTime;
141             idBits.clear();
142             for (uint32_t i = 0; i < msg.body.motion.pointerCount; i++) {
143                 uint32_t id = msg.body.motion.pointers[i].properties.id;
144                 idBits.markBit(id);
145                 idToIndex[id] = i;
146                 pointers[i].copyFrom(msg.body.motion.pointers[i].coords);
147             }
148         }
149 
initializeFromHistory150         void initializeFrom(const History& other) {
151             eventTime = other.eventTime;
152             idBits = other.idBits; // temporary copy
153             for (size_t i = 0; i < other.idBits.count(); i++) {
154                 uint32_t id = idBits.clearFirstMarkedBit();
155                 int32_t index = other.idToIndex[id];
156                 idToIndex[id] = index;
157                 pointers[index].copyFrom(other.pointers[index]);
158             }
159             idBits = other.idBits; // final copy
160         }
161 
getPointerByIdHistory162         const PointerCoords& getPointerById(uint32_t id) const { return pointers[idToIndex[id]]; }
163 
hasPointerIdHistory164         bool hasPointerId(uint32_t id) const { return idBits.hasBit(id); }
165     };
166     struct TouchState {
167         int32_t deviceId;
168         int32_t source;
169         size_t historyCurrent;
170         size_t historySize;
171         History history[2];
172         History lastResample;
173 
initializeTouchState174         void initialize(int32_t incomingDeviceId, int32_t incomingSource) {
175             deviceId = incomingDeviceId;
176             source = incomingSource;
177             historyCurrent = 0;
178             historySize = 0;
179             lastResample.eventTime = 0;
180             lastResample.idBits.clear();
181         }
182 
addHistoryTouchState183         void addHistory(const InputMessage& msg) {
184             historyCurrent ^= 1;
185             if (historySize < 2) {
186                 historySize += 1;
187             }
188             history[historyCurrent].initializeFrom(msg);
189         }
190 
getHistoryTouchState191         const History* getHistory(size_t index) const {
192             return &history[(historyCurrent + index) & 1];
193         }
194 
recentCoordinatesAreIdenticalTouchState195         bool recentCoordinatesAreIdentical(uint32_t id) const {
196             // Return true if the two most recently received "raw" coordinates are identical
197             if (historySize < 2) {
198                 return false;
199             }
200             if (!getHistory(0)->hasPointerId(id) || !getHistory(1)->hasPointerId(id)) {
201                 return false;
202             }
203             float currentX = getHistory(0)->getPointerById(id).getX();
204             float currentY = getHistory(0)->getPointerById(id).getY();
205             float previousX = getHistory(1)->getPointerById(id).getX();
206             float previousY = getHistory(1)->getPointerById(id).getY();
207             if (currentX == previousX && currentY == previousY) {
208                 return true;
209             }
210             return false;
211         }
212     };
213     std::vector<TouchState> mTouchStates;
214 
215     // Chain of batched sequence numbers.  When multiple input messages are combined into
216     // a batch, we append a record here that associates the last sequence number in the
217     // batch with the previous one.  When the finished signal is sent, we traverse the
218     // chain to individually finish all input messages that were part of the batch.
219     struct SeqChain {
220         uint32_t seq;   // sequence number of batched input message
221         uint32_t chain; // sequence number of previous batched input message
222     };
223     std::vector<SeqChain> mSeqChains;
224 
225     // The time at which each event with the sequence number 'seq' was consumed.
226     // This data is provided in 'finishInputEvent' so that the receiving end can measure the latency
227     // This collection is populated when the event is received, and the entries are erased when the
228     // events are finished. It should not grow infinitely because if an event is not ack'd, ANR
229     // will be raised for that connection, and no further events will be posted to that channel.
230     std::unordered_map<uint32_t /*seq*/, nsecs_t /*consumeTime*/> mConsumeTimes;
231 
232     status_t consumeBatch(InputEventFactoryInterface* factory, nsecs_t frameTime, uint32_t* outSeq,
233                           InputEvent** outEvent);
234     status_t consumeSamples(InputEventFactoryInterface* factory, Batch& batch, size_t count,
235                             uint32_t* outSeq, InputEvent** outEvent);
236 
237     void updateTouchState(InputMessage& msg);
238     void resampleTouchState(nsecs_t frameTime, MotionEvent* event, const InputMessage* next);
239 
240     ssize_t findBatch(int32_t deviceId, int32_t source) const;
241     ssize_t findTouchState(int32_t deviceId, int32_t source) const;
242 
243     nsecs_t getConsumeTime(uint32_t seq) const;
244     void popConsumeTime(uint32_t seq);
245     status_t sendUnchainedFinishedSignal(uint32_t seq, bool handled);
246 
247     static void rewriteMessage(TouchState& state, InputMessage& msg);
248     static bool canAddSample(const Batch& batch, const InputMessage* msg);
249     static ssize_t findSampleNoLaterThan(const Batch& batch, nsecs_t time);
250 
251     static bool isTouchResamplingEnabled();
252 };
253 
254 } // namespace android
255