• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 #ifndef _UI_INPUT_TRANSPORT_H
18 #define _UI_INPUT_TRANSPORT_H
19 
20 /**
21  * Native input transport.
22  *
23  * Uses anonymous shared memory as a whiteboard for sending input events from an
24  * InputPublisher to an InputConsumer and ensuring appropriate synchronization.
25  * One interesting feature is that published events can be updated in place as long as they
26  * have not yet been consumed.
27  *
28  * The InputPublisher and InputConsumer only take care of transferring event data
29  * over an InputChannel and sending synchronization signals.  The InputDispatcher and InputQueue
30  * build on these abstractions to add multiplexing and queueing.
31  */
32 
33 #include <semaphore.h>
34 #include <ui/Input.h>
35 #include <utils/Errors.h>
36 #include <utils/Timers.h>
37 #include <utils/RefBase.h>
38 #include <utils/String8.h>
39 
40 namespace android {
41 
42 /*
43  * An input channel consists of a shared memory buffer and a pair of pipes
44  * used to send input messages from an InputPublisher to an InputConsumer
45  * across processes.  Each channel has a descriptive name for debugging purposes.
46  *
47  * Each endpoint has its own InputChannel object that specifies its own file descriptors.
48  *
49  * The input channel is closed when all references to it are released.
50  */
51 class InputChannel : public RefBase {
52 protected:
53     virtual ~InputChannel();
54 
55 public:
56     InputChannel(const String8& name, int32_t ashmemFd, int32_t receivePipeFd,
57             int32_t sendPipeFd);
58 
59     /* Creates a pair of input channels and their underlying shared memory buffers
60      * and pipes.
61      *
62      * Returns OK on success.
63      */
64     static status_t openInputChannelPair(const String8& name,
65             sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
66 
getName()67     inline String8 getName() const { return mName; }
getAshmemFd()68     inline int32_t getAshmemFd() const { return mAshmemFd; }
getReceivePipeFd()69     inline int32_t getReceivePipeFd() const { return mReceivePipeFd; }
getSendPipeFd()70     inline int32_t getSendPipeFd() const { return mSendPipeFd; }
71 
72     /* Sends a signal to the other endpoint.
73      *
74      * Returns OK on success.
75      * Returns DEAD_OBJECT if the channel's peer has been closed.
76      * Other errors probably indicate that the channel is broken.
77      */
78     status_t sendSignal(char signal);
79 
80     /* Receives a signal send by the other endpoint.
81      * (Should only call this after poll() indicates that the receivePipeFd has available input.)
82      *
83      * Returns OK on success.
84      * Returns WOULD_BLOCK if there is no signal present.
85      * Returns DEAD_OBJECT if the channel's peer has been closed.
86      * Other errors probably indicate that the channel is broken.
87      */
88     status_t receiveSignal(char* outSignal);
89 
90 private:
91     String8 mName;
92     int32_t mAshmemFd;
93     int32_t mReceivePipeFd;
94     int32_t mSendPipeFd;
95 };
96 
97 /*
98  * Private intermediate representation of input events as messages written into an
99  * ashmem buffer.
100  */
101 struct InputMessage {
102     /* Semaphore count is set to 1 when the message is published.
103      * It becomes 0 transiently while the publisher updates the message.
104      * It becomes 0 permanently when the consumer consumes the message.
105      */
106     sem_t semaphore;
107 
108     /* Initialized to false by the publisher.
109      * Set to true by the consumer when it consumes the message.
110      */
111     bool consumed;
112 
113     int32_t type;
114 
115     struct SampleData {
116         nsecs_t eventTime;
117         PointerCoords coords[0]; // variable length
118     };
119 
120     int32_t deviceId;
121     int32_t source;
122 
123     union {
124         struct {
125             int32_t action;
126             int32_t flags;
127             int32_t keyCode;
128             int32_t scanCode;
129             int32_t metaState;
130             int32_t repeatCount;
131             nsecs_t downTime;
132             nsecs_t eventTime;
133         } key;
134 
135         struct {
136             int32_t action;
137             int32_t flags;
138             int32_t metaState;
139             int32_t buttonState;
140             int32_t edgeFlags;
141             nsecs_t downTime;
142             float xOffset;
143             float yOffset;
144             float xPrecision;
145             float yPrecision;
146             size_t pointerCount;
147             PointerProperties pointerProperties[MAX_POINTERS];
148             size_t sampleCount;
149             SampleData sampleData[0]; // variable length
150         } motion;
151     };
152 
153     /* Gets the number of bytes to add to step to the next SampleData object in a motion
154      * event message for a given number of pointers.
155      */
sampleDataStrideInputMessage156     static inline size_t sampleDataStride(size_t pointerCount) {
157         return sizeof(InputMessage::SampleData) + pointerCount * sizeof(PointerCoords);
158     }
159 
160     /* Adds the SampleData stride to the given pointer. */
sampleDataPtrIncrementInputMessage161     static inline SampleData* sampleDataPtrIncrement(SampleData* ptr, size_t stride) {
162         return reinterpret_cast<InputMessage::SampleData*>(reinterpret_cast<char*>(ptr) + stride);
163     }
164 };
165 
166 /*
167  * Publishes input events to an anonymous shared memory buffer.
168  * Uses atomic operations to coordinate shared access with a single concurrent consumer.
169  */
170 class InputPublisher {
171 public:
172     /* Creates a publisher associated with an input channel. */
173     explicit InputPublisher(const sp<InputChannel>& channel);
174 
175     /* Destroys the publisher and releases its input channel. */
176     ~InputPublisher();
177 
178     /* Gets the underlying input channel. */
getChannel()179     inline sp<InputChannel> getChannel() { return mChannel; }
180 
181     /* Prepares the publisher for use.  Must be called before it is used.
182      * Returns OK on success.
183      *
184      * This method implicitly calls reset(). */
185     status_t initialize();
186 
187     /* Resets the publisher to its initial state and unpins its ashmem buffer.
188      * Returns OK on success.
189      *
190      * Should be called after an event has been consumed to release resources used by the
191      * publisher until the next event is ready to be published.
192      */
193     status_t reset();
194 
195     /* Publishes a key event to the ashmem buffer.
196      *
197      * Returns OK on success.
198      * Returns INVALID_OPERATION if the publisher has not been reset.
199      */
200     status_t publishKeyEvent(
201             int32_t deviceId,
202             int32_t source,
203             int32_t action,
204             int32_t flags,
205             int32_t keyCode,
206             int32_t scanCode,
207             int32_t metaState,
208             int32_t repeatCount,
209             nsecs_t downTime,
210             nsecs_t eventTime);
211 
212     /* Publishes a motion event to the ashmem buffer.
213      *
214      * Returns OK on success.
215      * Returns INVALID_OPERATION if the publisher has not been reset.
216      * Returns BAD_VALUE if pointerCount is less than 1 or greater than MAX_POINTERS.
217      */
218     status_t publishMotionEvent(
219             int32_t deviceId,
220             int32_t source,
221             int32_t action,
222             int32_t flags,
223             int32_t edgeFlags,
224             int32_t metaState,
225             int32_t buttonState,
226             float xOffset,
227             float yOffset,
228             float xPrecision,
229             float yPrecision,
230             nsecs_t downTime,
231             nsecs_t eventTime,
232             size_t pointerCount,
233             const PointerProperties* pointerProperties,
234             const PointerCoords* pointerCoords);
235 
236     /* Appends a motion sample to a motion event unless already consumed.
237      *
238      * Returns OK on success.
239      * Returns INVALID_OPERATION if the current event is not a AMOTION_EVENT_ACTION_MOVE event.
240      * Returns FAILED_TRANSACTION if the current event has already been consumed.
241      * Returns NO_MEMORY if the buffer is full and no additional samples can be added.
242      */
243     status_t appendMotionSample(
244             nsecs_t eventTime,
245             const PointerCoords* pointerCoords);
246 
247     /* Sends a dispatch signal to the consumer to inform it that a new message is available.
248      *
249      * Returns OK on success.
250      * Errors probably indicate that the channel is broken.
251      */
252     status_t sendDispatchSignal();
253 
254     /* Receives the finished signal from the consumer in reply to the original dispatch signal.
255      * Returns whether the consumer handled the message.
256      *
257      * Returns OK on success.
258      * Returns WOULD_BLOCK if there is no signal present.
259      * Other errors probably indicate that the channel is broken.
260      */
261     status_t receiveFinishedSignal(bool* outHandled);
262 
263 private:
264     sp<InputChannel> mChannel;
265 
266     size_t mAshmemSize;
267     InputMessage* mSharedMessage;
268     bool mPinned;
269     bool mSemaphoreInitialized;
270     bool mWasDispatched;
271 
272     size_t mMotionEventPointerCount;
273     InputMessage::SampleData* mMotionEventSampleDataTail;
274     size_t mMotionEventSampleDataStride;
275 
276     status_t publishInputEvent(
277             int32_t type,
278             int32_t deviceId,
279             int32_t source);
280 };
281 
282 /*
283  * Consumes input events from an anonymous shared memory buffer.
284  * Uses atomic operations to coordinate shared access with a single concurrent publisher.
285  */
286 class InputConsumer {
287 public:
288     /* Creates a consumer associated with an input channel. */
289     explicit InputConsumer(const sp<InputChannel>& channel);
290 
291     /* Destroys the consumer and releases its input channel. */
292     ~InputConsumer();
293 
294     /* Gets the underlying input channel. */
getChannel()295     inline sp<InputChannel> getChannel() { return mChannel; }
296 
297     /* Prepares the consumer for use.  Must be called before it is used. */
298     status_t initialize();
299 
300     /* Consumes the input event in the buffer and copies its contents into
301      * an InputEvent object created using the specified factory.
302      * This operation will block if the publisher is updating the event.
303      *
304      * Returns OK on success.
305      * Returns INVALID_OPERATION if there is no currently published event.
306      * Returns NO_MEMORY if the event could not be created.
307      */
308     status_t consume(InputEventFactoryInterface* factory, InputEvent** outEvent);
309 
310     /* Sends a finished signal to the publisher to inform it that the current message is
311      * finished processing and specifies whether the message was handled by the consumer.
312      *
313      * Returns OK on success.
314      * Errors probably indicate that the channel is broken.
315      */
316     status_t sendFinishedSignal(bool handled);
317 
318     /* Receives the dispatched signal from the publisher.
319      *
320      * Returns OK on success.
321      * Returns WOULD_BLOCK if there is no signal present.
322      * Other errors probably indicate that the channel is broken.
323      */
324     status_t receiveDispatchSignal();
325 
326 private:
327     sp<InputChannel> mChannel;
328 
329     size_t mAshmemSize;
330     InputMessage* mSharedMessage;
331 
332     void populateKeyEvent(KeyEvent* keyEvent) const;
333     void populateMotionEvent(MotionEvent* motionEvent) const;
334 };
335 
336 } // namespace android
337 
338 #endif // _UI_INPUT_TRANSPORT_H
339