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