1 /*
2  ** Copyright 2015, 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 package com.android.server.accessibility;
18 
19 import android.os.Binder;
20 import android.os.Handler;
21 import android.os.Message;
22 import android.os.PowerManager;
23 import android.util.ArrayMap;
24 import android.util.Pools;
25 import android.util.Pools.Pool;
26 import android.util.Slog;
27 import android.view.InputEventConsistencyVerifier;
28 import android.view.KeyEvent;
29 
30 import com.android.server.policy.WindowManagerPolicy;
31 
32 import java.util.ArrayList;
33 import java.util.List;
34 import java.util.Map;
35 
36 /**
37  * Dispatcher to send KeyEvents to all accessibility services that are able to process them.
38  * Events that are handled by one or more services are consumed. Events that are not processed
39  * by any service (or time out before a service reports them as handled) are passed along to
40  * the rest of the system.
41  *
42  * The class assumes that services report their return values in order, which is valid because
43  * they process each call to {@code AccessibilityService.onKeyEvent} on a single thread, and so
44  * don't see the N+1th event until they have processed the Nth event.
45  */
46 public class KeyEventDispatcher implements Handler.Callback {
47     // Debugging
48     private static final String LOG_TAG = "KeyEventDispatcher";
49     private static final boolean DEBUG = false;
50     /* KeyEvents must be processed in this time interval */
51     private static final long ON_KEY_EVENT_TIMEOUT_MILLIS = 500;
52     public static final int MSG_ON_KEY_EVENT_TIMEOUT = 1;
53     private static final int MAX_POOL_SIZE = 10;
54 
55     private final Pool<PendingKeyEvent> mPendingEventPool = new Pools.SimplePool<>(MAX_POOL_SIZE);
56     private final Object mLock;
57 
58     /*
59      * Track events sent to each filter. If a KeyEvent is to be sent to at least one service,
60      * a corresponding PendingKeyEvent is created for it. This PendingKeyEvent is placed in
61      * the list for each service its KeyEvent is sent to. It is removed from the list when
62      * the service calls setOnKeyEventResult, or when we time out waiting for the service to
63      * respond.
64      */
65     private final Map<KeyEventFilter, ArrayList<PendingKeyEvent>> mPendingEventsMap =
66             new ArrayMap<>();
67 
68     private final InputEventConsistencyVerifier mSentEventsVerifier;
69     private final Handler mHandlerToSendKeyEventsToInputFilter;
70     private final int mMessageTypeForSendKeyEvent;
71     private final PowerManager mPowerManager;
72     private Handler mKeyEventTimeoutHandler;
73 
74     /**
75      * @param handlerToSendKeyEventsToInputFilter The handler to which to post {@code KeyEvent}s
76      * that have not been handled by any accessibility service.
77      * @param messageTypeForSendKeyEvent The field to populate {@code message.what} for the
78      * message that carries a {@code KeyEvent} to be sent to the input filter
79      * @param lock The lock used for all synchronization in this package. This lock must be held
80      * when calling {@code notifyKeyEventLocked}
81      * @param powerManager The power manager to alert to user activity if a KeyEvent is processed
82      * by a service
83      */
KeyEventDispatcher(Handler handlerToSendKeyEventsToInputFilter, int messageTypeForSendKeyEvent, Object lock, PowerManager powerManager)84     public KeyEventDispatcher(Handler handlerToSendKeyEventsToInputFilter,
85             int messageTypeForSendKeyEvent, Object lock, PowerManager powerManager) {
86         if (InputEventConsistencyVerifier.isInstrumentationEnabled()) {
87             mSentEventsVerifier = new InputEventConsistencyVerifier(
88                     this, 0, KeyEventDispatcher.class.getSimpleName());
89         } else {
90             mSentEventsVerifier = null;
91         }
92         mHandlerToSendKeyEventsToInputFilter = handlerToSendKeyEventsToInputFilter;
93         mMessageTypeForSendKeyEvent = messageTypeForSendKeyEvent;
94         mKeyEventTimeoutHandler =
95                 new Handler(handlerToSendKeyEventsToInputFilter.getLooper(), this);
96         mLock = lock;
97         mPowerManager = powerManager;
98     }
99 
100     /**
101      * See above for most params
102      * @param timeoutHandler Specify a handler to use for handling timeouts. This internal state is
103      * exposed for testing.
104      */
KeyEventDispatcher(Handler handlerToSendKeyEventsToInputFilter, int messageTypeForSendKeyEvent, Object lock, PowerManager powerManager, Handler timeoutHandler)105     public KeyEventDispatcher(Handler handlerToSendKeyEventsToInputFilter,
106             int messageTypeForSendKeyEvent, Object lock, PowerManager powerManager,
107             Handler timeoutHandler) {
108         this(handlerToSendKeyEventsToInputFilter, messageTypeForSendKeyEvent, lock, powerManager);
109         mKeyEventTimeoutHandler = timeoutHandler;
110     }
111 
112     /**
113      * Notify that a new KeyEvent is available to accessibility services. Must be called with the
114      * lock used to construct this object held. The keyEventFilters list must also be protected
115      * by the lock.
116      *
117      * @param event The new key event
118      * @param policyFlags Flags for the event
119      * @param keyEventFilters A list of keyEventFilters that should be considered for processing
120      * this event
121      *
122      * @return {@code true} if the event was passed to at least one AccessibilityService,
123      * {@code false} otherwise.
124      */
125     // TODO: The locking policy for keyEventFilters needs some thought.
notifyKeyEventLocked( KeyEvent event, int policyFlags, List<? extends KeyEventFilter> keyEventFilters)126     public boolean notifyKeyEventLocked(
127             KeyEvent event, int policyFlags, List<? extends KeyEventFilter> keyEventFilters) {
128         PendingKeyEvent pendingKeyEvent = null;
129         KeyEvent localClone = KeyEvent.obtain(event);
130         for (int i = 0; i < keyEventFilters.size(); i++) {
131             KeyEventFilter keyEventFilter = keyEventFilters.get(i);
132             if (keyEventFilter.onKeyEvent(localClone, localClone.getSequenceNumber())) {
133                 if (pendingKeyEvent == null) {
134                     pendingKeyEvent = obtainPendingEventLocked(localClone, policyFlags);
135                 }
136                 ArrayList<PendingKeyEvent> pendingEventList = mPendingEventsMap.get(keyEventFilter);
137                 if (pendingEventList == null) {
138                     pendingEventList = new ArrayList<>();
139                     mPendingEventsMap.put(keyEventFilter, pendingEventList);
140                 }
141                 pendingEventList.add(pendingKeyEvent);
142                 pendingKeyEvent.referenceCount++;
143             }
144         }
145 
146         if (pendingKeyEvent == null) {
147             localClone.recycle();
148             return false;
149         }
150 
151         Message message = mKeyEventTimeoutHandler.obtainMessage(
152                 MSG_ON_KEY_EVENT_TIMEOUT, pendingKeyEvent);
153         mKeyEventTimeoutHandler.sendMessageDelayed(message, ON_KEY_EVENT_TIMEOUT_MILLIS);
154         return true;
155     }
156 
157     /**
158      * Set the result from onKeyEvent from one service.
159      *
160      * @param keyEventFilter The filter setting the result
161      * @param handled {@code true} if the service handled the {@code KeyEvent}
162      * @param sequence The sequence number of the {@code KeyEvent}
163      */
setOnKeyEventResult(KeyEventFilter keyEventFilter, boolean handled, int sequence)164     public void setOnKeyEventResult(KeyEventFilter keyEventFilter, boolean handled, int sequence) {
165         synchronized (mLock) {
166             PendingKeyEvent pendingEvent =
167                     removeEventFromListLocked(mPendingEventsMap.get(keyEventFilter), sequence);
168             if (pendingEvent != null) {
169                 if (handled && !pendingEvent.handled) {
170                     pendingEvent.handled = handled;
171                     final long identity = Binder.clearCallingIdentity();
172                     try {
173                         mPowerManager.userActivity(pendingEvent.event.getEventTime(),
174                                 PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0);
175                     } finally {
176                         Binder.restoreCallingIdentity(identity);
177                     }
178                 }
179                 removeReferenceToPendingEventLocked(pendingEvent);
180             }
181         }
182     }
183 
184     /**
185      * Flush all pending key events for a service, treating all of them as unhandled
186      *
187      * @param keyEventFilter The filter for which to flush events
188      */
flush(KeyEventFilter keyEventFilter)189     public void flush(KeyEventFilter keyEventFilter) {
190         synchronized (mLock) {
191             List<PendingKeyEvent> pendingEvents = mPendingEventsMap.get(keyEventFilter);
192             if (pendingEvents != null) {
193                 for (int i = 0; i < pendingEvents.size(); i++) {
194                     PendingKeyEvent pendingEvent = pendingEvents.get(i);
195                     removeReferenceToPendingEventLocked(pendingEvent);
196                 }
197                 mPendingEventsMap.remove(keyEventFilter);
198             }
199         }
200     }
201 
202     @Override
handleMessage(Message message)203     public boolean handleMessage(Message message) {
204         if (message.what != MSG_ON_KEY_EVENT_TIMEOUT) {
205             Slog.w(LOG_TAG, "Unknown message: " + message.what);
206             return false;
207         }
208         PendingKeyEvent pendingKeyEvent = (PendingKeyEvent) message.obj;
209         synchronized (mLock) {
210             for (ArrayList<PendingKeyEvent> listForService : mPendingEventsMap.values()) {
211                 if (listForService.remove(pendingKeyEvent)) {
212                     if(removeReferenceToPendingEventLocked(pendingKeyEvent)) {
213                         break;
214                     }
215                 }
216             }
217         }
218         return true;
219     }
220 
obtainPendingEventLocked(KeyEvent event, int policyFlags)221     private PendingKeyEvent obtainPendingEventLocked(KeyEvent event, int policyFlags) {
222         PendingKeyEvent pendingEvent = mPendingEventPool.acquire();
223         if (pendingEvent == null) {
224             pendingEvent = new PendingKeyEvent();
225         }
226         pendingEvent.event = event;
227         pendingEvent.policyFlags = policyFlags;
228         pendingEvent.referenceCount = 0;
229         pendingEvent.handled = false;
230         return pendingEvent;
231     }
232 
removeEventFromListLocked( List<PendingKeyEvent> listOfEvents, int sequence)233     private static PendingKeyEvent removeEventFromListLocked(
234             List<PendingKeyEvent> listOfEvents, int sequence) {
235         /* In normal operation, the event should be first */
236         for (int i = 0; i < listOfEvents.size(); i++) {
237             PendingKeyEvent pendingKeyEvent = listOfEvents.get(i);
238             if (pendingKeyEvent.event.getSequenceNumber() == sequence) {
239                     /*
240                      * Removing the first element of the ArrayList can be slow if there are a lot
241                      * of events backed up, but for a handful of events it's better than incurring
242                      * the fixed overhead of LinkedList. An ArrayList optimized for removing the
243                      * first element (by treating the underlying array as a circular buffer) would
244                      * be ideal.
245                      */
246                 listOfEvents.remove(pendingKeyEvent);
247                 return pendingKeyEvent;
248             }
249         }
250         return null;
251     }
252 
253     /**
254      * @param pendingEvent The event whose reference count should be decreased
255      * @return {@code true} if the event was release, {@code false} if not.
256      */
removeReferenceToPendingEventLocked(PendingKeyEvent pendingEvent)257     private boolean removeReferenceToPendingEventLocked(PendingKeyEvent pendingEvent) {
258         if (--pendingEvent.referenceCount > 0) {
259             return false;
260         }
261         mKeyEventTimeoutHandler.removeMessages(MSG_ON_KEY_EVENT_TIMEOUT, pendingEvent);
262         if (!pendingEvent.handled) {
263                 /* Pass event to input filter */
264             if (DEBUG) {
265                 Slog.i(LOG_TAG, "Injecting event: " + pendingEvent.event);
266             }
267             if (mSentEventsVerifier != null) {
268                 mSentEventsVerifier.onKeyEvent(pendingEvent.event, 0);
269             }
270             int policyFlags = pendingEvent.policyFlags | WindowManagerPolicy.FLAG_PASS_TO_USER;
271             mHandlerToSendKeyEventsToInputFilter
272                     .obtainMessage(mMessageTypeForSendKeyEvent, policyFlags, 0, pendingEvent.event)
273                     .sendToTarget();
274         } else {
275             pendingEvent.event.recycle();
276         }
277         mPendingEventPool.release(pendingEvent);
278         return true;
279     }
280 
281     private static final class PendingKeyEvent {
282         /* Event and policyFlag provided in notifyKeyEventLocked */
283         KeyEvent event;
284         int policyFlags;
285         /*
286          * The referenceCount optimizes the process of determining the number of services
287          * still holding a KeyEvent. It must be equal to the number of times the PendingEvent
288          * appears in mPendingEventsMap, or PendingEvents will leak.
289          */
290         int referenceCount;
291         /* Whether or not at least one service had handled this event */
292         boolean handled;
293     }
294 
295     public interface KeyEventFilter {
296         /**
297          * Filter a key event if possible
298          *
299          * @param event The event to filter
300          * @param sequenceNumber The sequence number of the event
301          *
302          * @return {@code true} if the filter is active and will call back with status.
303          * {@code false} if the filter is not active and will ignore the event
304          */
onKeyEvent(KeyEvent event, int sequenceNumber)305         boolean onKeyEvent(KeyEvent event, int sequenceNumber);
306     }
307 }
308