OSDN Git Service

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