1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
|
/**
* Copyright 2024 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 <functional>
#include <map>
#include <memory>
#include <optional>
#include <input/Input.h>
#include <input/InputTransport.h>
#include <input/Resampler.h>
#include <utils/Looper.h>
namespace android {
/**
* An interface to receive batched input events. Even if you don't want batching, you still have to
* use this interface, and some of the events will be batched if your implementation is slow to
* handle the incoming input. The events received by these callbacks are never null.
*/
class InputConsumerCallbacks {
public:
virtual ~InputConsumerCallbacks(){};
virtual void onKeyEvent(std::unique_ptr<KeyEvent> event, uint32_t seq) = 0;
virtual void onMotionEvent(std::unique_ptr<MotionEvent> event, uint32_t seq) = 0;
/**
* When you receive this callback, you must (eventually) call "consumeBatchedInputEvents".
* If you don't want batching, then call "consumeBatchedInputEvents" immediately with
* std::nullopt requestedFrameTime to receive the pending motion event(s).
* @param pendingBatchSource the source of the pending batch.
*/
virtual void onBatchedInputEventPending(int32_t pendingBatchSource) = 0;
virtual void onFocusEvent(std::unique_ptr<FocusEvent> event, uint32_t seq) = 0;
virtual void onCaptureEvent(std::unique_ptr<CaptureEvent> event, uint32_t seq) = 0;
virtual void onDragEvent(std::unique_ptr<DragEvent> event, uint32_t seq) = 0;
virtual void onTouchModeEvent(std::unique_ptr<TouchModeEvent> event, uint32_t seq) = 0;
};
/**
* Consumes input events from an input channel.
*
* This is a re-implementation of InputConsumer. At the moment it only supports resampling for
* single pointer events. A lot of the higher-level logic has been folded into this class, to make
* it easier to use. In the legacy class, InputConsumer, the consumption logic was partially handled
* in the jni layer, as well as various actions like adding the fd to the Choreographer.
*
* TODO(b/297226446): use this instead of "InputConsumer":
* - Add resampling for multiple pointer events.
* - Allow various resampling strategies to be specified
* - Delete the old "InputConsumer" and use this class instead, renaming it to "InputConsumer".
* - Add tracing
* - Update all tests to use the new InputConsumer
*
* This class is not thread-safe. We are currently allowing the constructor to run on any thread,
* but all of the remaining APIs should be invoked on the looper thread only.
*/
class InputConsumerNoResampling final {
public:
/**
* @param callbacks are used to interact with InputConsumerNoResampling. They're called whenever
* the event is ready to consume.
* @param looper needs to be sp and not shared_ptr because it inherits from
* RefBase
* @param resamplerCreator callable that returns the resampling strategy to be used. If null, no
* resampling will be performed. resamplerCreator must never return nullptr.
*/
explicit InputConsumerNoResampling(
const std::shared_ptr<InputChannel>& channel, sp<Looper> looper,
InputConsumerCallbacks& callbacks,
std::function<std::unique_ptr<Resampler>()> resamplerCreator);
~InputConsumerNoResampling();
/**
* Must be called exactly once for each event received through the callbacks.
*/
void finishInputEvent(uint32_t seq, bool handled);
void reportTimeline(int32_t inputEventId, nsecs_t gpuCompletedTime, nsecs_t presentTime);
/**
* If you want to consume all events immediately (disable batching), then you still must call
* this. For requestedFrameTime, use a std::nullopt. It is not guaranteed that the consumption
* will occur at requestedFrameTime. The resampling strategy may modify it.
* @param requestedFrameTime the time up to which consume the events. When there's double (or
* triple) buffering, you may want to not consume all events currently available, because you
* could be still working on an older frame, but there could already have been events that
* arrived that are more recent.
* @return whether any events were actually consumed
*/
bool consumeBatchedInputEvents(std::optional<nsecs_t> requestedFrameTime);
/**
* Returns true when there is *likely* a pending batch or a pending event in the channel.
*
* This is only a performance hint and may return false negative results. Clients should not
* rely on availability of the message based on the return value.
*/
bool probablyHasInput() const;
std::string getName() { return mChannel->getName(); }
std::string dump() const;
private:
std::shared_ptr<InputChannel> mChannel;
sp<Looper> mLooper;
InputConsumerCallbacks& mCallbacks;
const std::function<std::unique_ptr<Resampler>()> mResamplerCreator;
/**
* A map to manage multidevice resampling. Each contained resampler is never null. This map is
* only modified by handleMessages.
*/
std::map<DeviceId, std::unique_ptr<Resampler>> mResamplers;
// Looper-related infrastructure
/**
* This class is needed to associate the function "handleReceiveCallback" with the provided
* looper. The callback sent to the looper is RefBase - based, so we can't just send a reference
* of this class directly to the looper.
*/
class LooperEventCallback : public LooperCallback {
public:
LooperEventCallback(std::function<int(int events)> callback) : mCallback(callback) {}
int handleEvent(int /*fd*/, int events, void* /*data*/) override {
return mCallback(events);
}
private:
const std::function<int(int events)> mCallback;
};
sp<LooperEventCallback> mCallback;
/**
* The actual code that executes when the looper encounters available data on the InputChannel.
*/
int handleReceiveCallback(int events);
int mFdEvents;
void setFdEvents(int events);
void ensureCalledOnLooperThread(const char* func) const;
// Event-reading infrastructure
/**
* A fifo queue of events to be sent to the InputChannel. We can't send all InputMessages to
* the channel immediately when they are produced, because it's possible that the InputChannel
* is blocked (if the channel buffer is full). When that happens, we don't want to drop the
* events. Therefore, events should only be erased from the queue after they've been
* successfully written to the InputChannel.
*/
std::queue<InputMessage> mOutboundQueue;
/**
* Try to send all of the events in mOutboundQueue over the InputChannel. Not all events might
* actually get sent, because it's possible that the channel is blocked.
*/
void processOutboundEvents();
/**
* 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;
/**
* Find and return the consumeTime associated with the provided sequence number. Crashes if
* the provided seq number is not found.
*/
nsecs_t popConsumeTime(uint32_t seq);
// Event reading and processing
/**
* Read all of the available events from the InputChannel
*/
std::vector<InputMessage> readAllMessages();
/**
* Send InputMessage to the corresponding InputConsumerCallbacks function.
* @param msg
*/
void handleMessage(const InputMessage& msg) const;
// Batching
/**
* Batch messages that can be batched. When an unbatchable message is encountered, send it
* to the InputConsumerCallbacks immediately. If there are batches remaining,
* notify InputConsumerCallbacks. If a resampleable ACTION_DOWN message is received, then a
* resampler is inserted for that deviceId in mResamplers. If a resampleable ACTION_UP or
* ACTION_CANCEL message is received then the resampler associated to that deviceId is erased
* from mResamplers.
*/
void handleMessages(std::vector<InputMessage>&& messages);
/**
* Batched InputMessages, per deviceId.
* For each device, we are storing a queue of batched messages. These will all be collapsed into
* a single MotionEvent (up to a specific requestedFrameTime) when the consumer calls
* `consumeBatchedInputEvents`.
*/
std::map<DeviceId, std::queue<InputMessage>> mBatches;
/**
* Creates a MotionEvent by consuming samples from the provided queue. Consumes all messages
* with eventTime <= requestedFrameTime - resampleLatency, where `resampleLatency` is latency
* introduced by the resampler. Assumes that messages are queued in chronological order.
* @param requestedFrameTime The time up to which consume messages, as given by the inequality
* above. If std::nullopt, everything in messages will be consumed.
* @param messages the queue of messages to consume from.
*/
std::pair<std::unique_ptr<MotionEvent>, std::optional<uint32_t>> createBatchedMotionEvent(
const std::optional<nsecs_t> requestedFrameTime, std::queue<InputMessage>& messages);
/**
* Consumes the batched input events, optionally allowing the caller to specify a device id
* and/or requestedFrameTime threshold. It is not guaranteed that consumption will occur at
* requestedFrameTime.
* @param deviceId The device id from which to consume events. If std::nullopt, consumes events
* from any device id.
* @param requestedFrameTime The time up to which consume the events. If std::nullopt, consumes
* input events with any timestamp.
* @return Whether or not any events were consumed.
*/
bool consumeBatchedInputEvents(std::optional<DeviceId> deviceId,
std::optional<nsecs_t> requestedFrameTime);
/**
* A map from a single sequence number to several sequence numbers. This is needed because of
* batching. When batching is enabled, a single MotionEvent will contain several samples. Each
* sample came from an individual InputMessage of Type::Motion, and therefore will have to be
* finished individually. Therefore, when the app calls "finish" on a (possibly batched)
* MotionEvent, we will need to check this map in case there are multiple sequence numbers
* associated with a single number that the app provided.
*
* For example:
* Suppose we received 4 InputMessage's of type Motion, with action MOVE:
* InputMessage(MOVE) InputMessage(MOVE) InputMessage(MOVE) InputMessage(MOVE)
* seq=10 seq=11 seq=12 seq=13
* The app consumed them all as a batch, which means that the app received a single MotionEvent
* with historySize=3 and seq = 10.
*
* This map will look like:
* {
* 10: [11, 12, 13],
* }
* So the sequence number 10 will have 3 other sequence numbers associated with it.
* When the app calls 'finish' for seq=10, we need to call 'finish' 4 times total, for sequence
* numbers 10, 11, 12, 13. The app is not aware of the sequence numbers of each sample inside
* the batched MotionEvent that it received.
*/
std::map<uint32_t, std::vector<uint32_t>> mBatchedSequenceNumbers;
};
} // namespace android
|