• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  ** Copyright 2017, 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 static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE;
20 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER;
21 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_STATUS;
22 import static android.accessibilityservice.AccessibilityService.KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP;
23 import static android.accessibilityservice.AccessibilityServiceInfo.DEFAULT;
24 import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
25 import static android.view.accessibility.AccessibilityInteractionClient.CALL_STACK;
26 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS;
27 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLEAR_ACCESSIBILITY_FOCUS;
28 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
29 import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
30 
31 import android.accessibilityservice.AccessibilityGestureEvent;
32 import android.accessibilityservice.AccessibilityService;
33 import android.accessibilityservice.AccessibilityServiceInfo;
34 import android.accessibilityservice.IAccessibilityServiceClient;
35 import android.accessibilityservice.IAccessibilityServiceConnection;
36 import android.annotation.NonNull;
37 import android.annotation.Nullable;
38 import android.app.PendingIntent;
39 import android.content.ComponentName;
40 import android.content.Context;
41 import android.content.Intent;
42 import android.content.ServiceConnection;
43 import android.content.pm.PackageManager;
44 import android.content.pm.ParceledListSlice;
45 import android.graphics.ParcelableColorSpace;
46 import android.graphics.Region;
47 import android.hardware.HardwareBuffer;
48 import android.hardware.display.DisplayManager;
49 import android.hardware.display.DisplayManagerInternal;
50 import android.os.Binder;
51 import android.os.Build;
52 import android.os.Bundle;
53 import android.os.Handler;
54 import android.os.IBinder;
55 import android.os.Looper;
56 import android.os.Message;
57 import android.os.PowerManager;
58 import android.os.RemoteCallback;
59 import android.os.RemoteException;
60 import android.os.ServiceManager;
61 import android.os.SystemClock;
62 import android.util.Slog;
63 import android.util.SparseArray;
64 import android.view.Display;
65 import android.view.KeyEvent;
66 import android.view.MagnificationSpec;
67 import android.view.SurfaceControl.ScreenshotHardwareBuffer;
68 import android.view.View;
69 import android.view.WindowInfo;
70 import android.view.accessibility.AccessibilityCache;
71 import android.view.accessibility.AccessibilityEvent;
72 import android.view.accessibility.AccessibilityNodeInfo;
73 import android.view.accessibility.AccessibilityWindowInfo;
74 import android.view.accessibility.IAccessibilityInteractionConnectionCallback;
75 
76 import com.android.internal.annotations.GuardedBy;
77 import com.android.internal.compat.IPlatformCompat;
78 import com.android.internal.os.SomeArgs;
79 import com.android.internal.util.DumpUtils;
80 import com.android.internal.util.function.pooled.PooledLambda;
81 import com.android.server.LocalServices;
82 import com.android.server.accessibility.AccessibilityWindowManager.RemoteAccessibilityConnection;
83 import com.android.server.accessibility.magnification.FullScreenMagnificationController;
84 import com.android.server.wm.ActivityTaskManagerInternal;
85 import com.android.server.wm.WindowManagerInternal;
86 
87 import java.io.FileDescriptor;
88 import java.io.PrintWriter;
89 import java.util.ArrayList;
90 import java.util.Arrays;
91 import java.util.Collections;
92 import java.util.HashSet;
93 import java.util.List;
94 import java.util.NoSuchElementException;
95 import java.util.Set;
96 
97 /**
98  * This class represents an accessibility client - either an AccessibilityService or a UiAutomation.
99  * It is responsible for behavior common to both types of clients.
100  */
101 abstract class AbstractAccessibilityServiceConnection extends IAccessibilityServiceConnection.Stub
102         implements ServiceConnection, IBinder.DeathRecipient, KeyEventDispatcher.KeyEventFilter,
103         FingerprintGestureDispatcher.FingerprintGestureClient {
104     private static final boolean DEBUG = false;
105     private static final String LOG_TAG = "AbstractAccessibilityServiceConnection";
106     private static final String TRACE_A11Y_SERVICE_CONNECTION =
107             LOG_TAG + ".IAccessibilityServiceConnection";
108     private static final String TRACE_A11Y_SERVICE_CLIENT =
109             LOG_TAG + ".IAccessibilityServiceClient";
110     private static final int WAIT_WINDOWS_TIMEOUT_MILLIS = 5000;
111 
112     protected static final String TAKE_SCREENSHOT = "takeScreenshot";
113     protected final Context mContext;
114     protected final SystemSupport mSystemSupport;
115     protected final WindowManagerInternal mWindowManagerService;
116     private final SystemActionPerformer mSystemActionPerformer;
117     private final AccessibilityWindowManager mA11yWindowManager;
118     private final DisplayManager mDisplayManager;
119     private final PowerManager mPowerManager;
120     private final IPlatformCompat mIPlatformCompat;
121 
122     private final Handler mMainHandler;
123 
124     // Handler for scheduling method invocations on the main thread.
125     public final InvocationHandler mInvocationHandler;
126 
127     final int mId;
128 
129     protected final AccessibilityServiceInfo mAccessibilityServiceInfo;
130 
131     // Lock must match the one used by AccessibilityManagerService
132     protected final Object mLock;
133 
134     protected final AccessibilitySecurityPolicy mSecurityPolicy;
135     protected final AccessibilityTrace mTrace;
136 
137     // The service that's bound to this instance. Whenever this value is non-null, this
138     // object is registered as a death recipient
139     IBinder mService;
140 
141     IAccessibilityServiceClient mServiceInterface;
142 
143     int mEventTypes;
144 
145     int mFeedbackType;
146 
147     Set<String> mPackageNames = new HashSet<>();
148 
149     boolean mIsDefault;
150 
151     boolean mRequestTouchExplorationMode;
152 
153     private boolean mServiceHandlesDoubleTap;
154 
155     private boolean mRequestMultiFingerGestures;
156 
157     private boolean mRequestTwoFingerPassthrough;
158 
159     private boolean mSendMotionEvents;
160 
161     boolean mRequestFilterKeyEvents;
162 
163     boolean mRetrieveInteractiveWindows;
164 
165     boolean mCaptureFingerprintGestures;
166 
167     boolean mRequestAccessibilityButton;
168 
169     boolean mReceivedAccessibilityButtonCallbackSinceBind;
170 
171     boolean mLastAccessibilityButtonCallbackState;
172 
173     int mFetchFlags;
174 
175     long mNotificationTimeout;
176 
177     final ComponentName mComponentName;
178 
179     // the events pending events to be dispatched to this service
180     final SparseArray<AccessibilityEvent> mPendingEvents = new SparseArray<>();
181 
182     /** Whether this service relies on its {@link AccessibilityCache} being up to date */
183     boolean mUsesAccessibilityCache = false;
184 
185     // Handler only for dispatching accessibility events since we use event
186     // types as message types allowing us to remove messages per event type.
187     public Handler mEventDispatchHandler;
188 
189     final SparseArray<IBinder> mOverlayWindowTokens = new SparseArray();
190 
191     /** The timestamp of requesting to take screenshot in milliseconds */
192     private long mRequestTakeScreenshotTimestampMs;
193 
194     public interface SystemSupport {
195         /**
196          * @return The current dispatcher for key events
197          */
getKeyEventDispatcher()198         @NonNull KeyEventDispatcher getKeyEventDispatcher();
199 
200         /**
201          * @param windowId The id of the window of interest
202          * @return The magnification spec for the window, or {@code null} if none is available
203          */
getCompatibleMagnificationSpecLocked(int windowId)204         @Nullable MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId);
205 
206         /**
207          * @param displayId The display id.
208          * @return The current injector of motion events used on the display, if one exists.
209          */
getMotionEventInjectorForDisplayLocked(int displayId)210         @Nullable MotionEventInjector getMotionEventInjectorForDisplayLocked(int displayId);
211 
212         /**
213          * @return The current dispatcher for fingerprint gestures, if one exists
214          */
getFingerprintGestureDispatcher()215         @Nullable FingerprintGestureDispatcher getFingerprintGestureDispatcher();
216 
217         /**
218          * @return The magnification controller
219          */
220         @NonNull
getFullScreenMagnificationController()221         FullScreenMagnificationController getFullScreenMagnificationController();
222 
223         /**
224          * Called back to notify system that the client has changed
225          * @param serviceInfoChanged True if the service's AccessibilityServiceInfo changed.
226          */
onClientChangeLocked(boolean serviceInfoChanged)227         void onClientChangeLocked(boolean serviceInfoChanged);
228 
getCurrentUserIdLocked()229         int getCurrentUserIdLocked();
230 
isAccessibilityButtonShown()231         boolean isAccessibilityButtonShown();
232 
233         /**
234          * Persists the component names in the specified setting in a
235          * colon separated fashion.
236          *
237          * @param settingName The setting name.
238          * @param componentNames The component names.
239          * @param userId The user id to persist the setting for.
240          */
persistComponentNamesToSettingLocked(String settingName, Set<ComponentName> componentNames, int userId)241         void persistComponentNamesToSettingLocked(String settingName,
242                 Set<ComponentName> componentNames, int userId);
243 
244         /* This is exactly PendingIntent.getActivity, separated out for testability */
getPendingIntentActivity(Context context, int requestCode, Intent intent, int flags)245         PendingIntent getPendingIntentActivity(Context context, int requestCode, Intent intent,
246                 int flags);
247 
setGestureDetectionPassthroughRegion(int displayId, Region region)248         void setGestureDetectionPassthroughRegion(int displayId, Region region);
249 
setTouchExplorationPassthroughRegion(int displayId, Region region)250         void setTouchExplorationPassthroughRegion(int displayId, Region region);
251     }
252 
AbstractAccessibilityServiceConnection(Context context, ComponentName componentName, AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler, Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport, AccessibilityTrace trace, WindowManagerInternal windowManagerInternal, SystemActionPerformer systemActionPerfomer, AccessibilityWindowManager a11yWindowManager)253     public AbstractAccessibilityServiceConnection(Context context, ComponentName componentName,
254             AccessibilityServiceInfo accessibilityServiceInfo, int id, Handler mainHandler,
255             Object lock, AccessibilitySecurityPolicy securityPolicy, SystemSupport systemSupport,
256             AccessibilityTrace trace, WindowManagerInternal windowManagerInternal,
257             SystemActionPerformer systemActionPerfomer,
258             AccessibilityWindowManager a11yWindowManager) {
259         mContext = context;
260         mWindowManagerService = windowManagerInternal;
261         mId = id;
262         mComponentName = componentName;
263         mAccessibilityServiceInfo = accessibilityServiceInfo;
264         mLock = lock;
265         mSecurityPolicy = securityPolicy;
266         mSystemActionPerformer = systemActionPerfomer;
267         mSystemSupport = systemSupport;
268         mTrace = trace;
269         mMainHandler = mainHandler;
270         mInvocationHandler = new InvocationHandler(mainHandler.getLooper());
271         mA11yWindowManager = a11yWindowManager;
272         mDisplayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
273         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
274         mIPlatformCompat = IPlatformCompat.Stub.asInterface(
275                 ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
276         mEventDispatchHandler = new Handler(mainHandler.getLooper()) {
277             @Override
278             public void handleMessage(Message message) {
279                 final int eventType =  message.what;
280                 AccessibilityEvent event = (AccessibilityEvent) message.obj;
281                 boolean serviceWantsEvent = message.arg1 != 0;
282                 notifyAccessibilityEventInternal(eventType, event, serviceWantsEvent);
283             }
284         };
285         setDynamicallyConfigurableProperties(accessibilityServiceInfo);
286     }
287 
288     @Override
onKeyEvent(KeyEvent keyEvent, int sequenceNumber)289     public boolean onKeyEvent(KeyEvent keyEvent, int sequenceNumber) {
290         if (!mRequestFilterKeyEvents || (mServiceInterface == null)) {
291             return false;
292         }
293         if((mAccessibilityServiceInfo.getCapabilities()
294                 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FILTER_KEY_EVENTS) == 0) {
295             return false;
296         }
297         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
298             return false;
299         }
300         try {
301             if (mTrace.isA11yTracingEnabled()) {
302                 mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onKeyEvent",
303                         keyEvent + ", " + sequenceNumber);
304             }
305             mServiceInterface.onKeyEvent(keyEvent, sequenceNumber);
306         } catch (RemoteException e) {
307             return false;
308         }
309         return true;
310     }
311 
setDynamicallyConfigurableProperties(AccessibilityServiceInfo info)312     public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) {
313         mEventTypes = info.eventTypes;
314         mFeedbackType = info.feedbackType;
315         String[] packageNames = info.packageNames;
316         mPackageNames.clear();
317         if (packageNames != null) {
318             mPackageNames.addAll(Arrays.asList(packageNames));
319         }
320         mNotificationTimeout = info.notificationTimeout;
321         mIsDefault = (info.flags & DEFAULT) != 0;
322 
323         if (supportsFlagForNotImportantViews(info)) {
324             if ((info.flags & AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) != 0) {
325                 mFetchFlags |= AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
326             } else {
327                 mFetchFlags &= ~AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS;
328             }
329         }
330 
331         if ((info.flags & AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS) != 0) {
332             mFetchFlags |= AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
333         } else {
334             mFetchFlags &= ~AccessibilityNodeInfo.FLAG_REPORT_VIEW_IDS;
335         }
336 
337         mRequestTouchExplorationMode = (info.flags
338                 & AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE) != 0;
339         mServiceHandlesDoubleTap = (info.flags
340                 & AccessibilityServiceInfo.FLAG_SERVICE_HANDLES_DOUBLE_TAP) != 0;
341         mRequestMultiFingerGestures = (info.flags
342                 & AccessibilityServiceInfo.FLAG_REQUEST_MULTI_FINGER_GESTURES) != 0;
343         mRequestTwoFingerPassthrough =
344                 (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_2_FINGER_PASSTHROUGH) != 0;
345         mSendMotionEvents =
346                 (info.flags & AccessibilityServiceInfo.FLAG_SEND_MOTION_EVENTS) != 0;
347         mRequestFilterKeyEvents =
348                 (info.flags & AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS) != 0;
349         mRetrieveInteractiveWindows = (info.flags
350                 & AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS) != 0;
351         mCaptureFingerprintGestures = (info.flags
352                 & AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES) != 0;
353         mRequestAccessibilityButton = (info.flags
354                 & AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON) != 0;
355     }
356 
supportsFlagForNotImportantViews(AccessibilityServiceInfo info)357     protected boolean supportsFlagForNotImportantViews(AccessibilityServiceInfo info) {
358         return info.getResolveInfo().serviceInfo.applicationInfo.targetSdkVersion
359                 >= Build.VERSION_CODES.JELLY_BEAN;
360     }
361 
canReceiveEventsLocked()362     public boolean canReceiveEventsLocked() {
363         return (mEventTypes != 0 && mService != null);
364     }
365 
366     @Override
setOnKeyEventResult(boolean handled, int sequence)367     public void setOnKeyEventResult(boolean handled, int sequence) {
368         if (mTrace.isA11yTracingEnabled()) {
369             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setOnKeyEventResult",
370                     "handled=" + handled + ";sequence=" + sequence);
371         }
372         mSystemSupport.getKeyEventDispatcher().setOnKeyEventResult(this, handled, sequence);
373     }
374 
375     @Override
getServiceInfo()376     public AccessibilityServiceInfo getServiceInfo() {
377         if (mTrace.isA11yTracingEnabled()) {
378             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getServiceInfo");
379         }
380         synchronized (mLock) {
381             return mAccessibilityServiceInfo;
382         }
383     }
384 
getCapabilities()385     public int getCapabilities() {
386         return mAccessibilityServiceInfo.getCapabilities();
387     }
388 
getRelevantEventTypes()389     int getRelevantEventTypes() {
390         return (mUsesAccessibilityCache ? AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK
391                 : AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) | mEventTypes;
392     }
393 
394     @Override
setServiceInfo(AccessibilityServiceInfo info)395     public void setServiceInfo(AccessibilityServiceInfo info) {
396         if (mTrace.isA11yTracingEnabled()) {
397             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setServiceInfo", "info=" + info);
398         }
399         final long identity = Binder.clearCallingIdentity();
400         try {
401             synchronized (mLock) {
402                 // If the XML manifest had data to configure the service its info
403                 // should be already set. In such a case update only the dynamically
404                 // configurable properties.
405                 AccessibilityServiceInfo oldInfo = mAccessibilityServiceInfo;
406                 if (oldInfo != null) {
407                     oldInfo.updateDynamicallyConfigurableProperties(mIPlatformCompat, info);
408                     setDynamicallyConfigurableProperties(oldInfo);
409                 } else {
410                     setDynamicallyConfigurableProperties(info);
411                 }
412                 mSystemSupport.onClientChangeLocked(true);
413             }
414         } finally {
415             Binder.restoreCallingIdentity(identity);
416         }
417     }
418 
hasRightsToCurrentUserLocked()419     protected abstract boolean hasRightsToCurrentUserLocked();
420 
421     @Nullable
422     @Override
getWindows()423     public AccessibilityWindowInfo.WindowListSparseArray getWindows() {
424         if (mTrace.isA11yTracingEnabled()) {
425             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindows");
426         }
427         synchronized (mLock) {
428             if (!hasRightsToCurrentUserLocked()) {
429                 return null;
430             }
431             final boolean permissionGranted =
432                     mSecurityPolicy.canRetrieveWindowsLocked(this);
433             if (!permissionGranted) {
434                 return null;
435             }
436             if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
437                 return null;
438             }
439             final AccessibilityWindowInfo.WindowListSparseArray allWindows =
440                     new AccessibilityWindowInfo.WindowListSparseArray();
441             final ArrayList<Integer> displayList = mA11yWindowManager.getDisplayListLocked();
442             final int displayListCounts = displayList.size();
443             if (displayListCounts > 0) {
444                 for (int i = 0; i < displayListCounts; i++) {
445                     final int displayId = displayList.get(i);
446                     ensureWindowsAvailableTimedLocked(displayId);
447 
448                     final List<AccessibilityWindowInfo> windowList = getWindowsByDisplayLocked(
449                             displayId);
450                     if (windowList != null) {
451                         allWindows.put(displayId, windowList);
452                     }
453                 }
454             }
455             return allWindows;
456         }
457     }
458 
459     @Override
getWindow(int windowId)460     public AccessibilityWindowInfo getWindow(int windowId) {
461         if (mTrace.isA11yTracingEnabled()) {
462             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindow", "windowId=" + windowId);
463         }
464         synchronized (mLock) {
465             int displayId = Display.INVALID_DISPLAY;
466             if (windowId != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID) {
467                 displayId = mA11yWindowManager.getDisplayIdByUserIdAndWindowIdLocked(
468                         mSystemSupport.getCurrentUserIdLocked(), windowId);
469             }
470             ensureWindowsAvailableTimedLocked(displayId);
471 
472             if (!hasRightsToCurrentUserLocked()) {
473                 return null;
474             }
475             final boolean permissionGranted =
476                     mSecurityPolicy.canRetrieveWindowsLocked(this);
477             if (!permissionGranted) {
478                 return null;
479             }
480             if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
481                 return null;
482             }
483             AccessibilityWindowInfo window =
484                     mA11yWindowManager.findA11yWindowInfoByIdLocked(windowId);
485             if (window != null) {
486                 AccessibilityWindowInfo windowClone = AccessibilityWindowInfo.obtain(window);
487                 windowClone.setConnectionId(mId);
488                 return windowClone;
489             }
490             return null;
491         }
492     }
493 
494     @Override
findAccessibilityNodeInfosByViewId(int accessibilityWindowId, long accessibilityNodeId, String viewIdResName, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)495     public String[] findAccessibilityNodeInfosByViewId(int accessibilityWindowId,
496             long accessibilityNodeId, String viewIdResName, int interactionId,
497             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
498             throws RemoteException {
499         if (mTrace.isA11yTracingEnabled()) {
500             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfosByViewId",
501                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
502                     + accessibilityNodeId + ";viewIdResName=" + viewIdResName + ";interactionId="
503                     + interactionId + ";callback=" + callback + ";interrogatingTid="
504                     + interrogatingTid);
505         }
506         final int resolvedWindowId;
507         RemoteAccessibilityConnection connection;
508         Region partialInteractiveRegion = Region.obtain();
509         MagnificationSpec spec;
510         synchronized (mLock) {
511             mUsesAccessibilityCache = true;
512             if (!hasRightsToCurrentUserLocked()) {
513                 return null;
514             }
515             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
516             final boolean permissionGranted =
517                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
518                             mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId);
519             if (!permissionGranted) {
520                 return null;
521             } else {
522                 connection = mA11yWindowManager.getConnectionLocked(
523                         mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId);
524                 if (connection == null) {
525                     return null;
526                 }
527             }
528             if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
529                     resolvedWindowId, partialInteractiveRegion)) {
530                 partialInteractiveRegion.recycle();
531                 partialInteractiveRegion = null;
532             }
533             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
534         }
535         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
536             return null;
537         }
538         final int interrogatingPid = Binder.getCallingPid();
539         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
540                 interrogatingPid, interrogatingTid);
541         final long identityToken = Binder.clearCallingIdentity();
542         try {
543             connection.getRemote().findAccessibilityNodeInfosByViewId(accessibilityNodeId,
544                     viewIdResName, partialInteractiveRegion, interactionId, callback, mFetchFlags,
545                     interrogatingPid, interrogatingTid, spec);
546             return mSecurityPolicy.computeValidReportedPackages(
547                     connection.getPackageName(), connection.getUid());
548         } catch (RemoteException re) {
549             if (DEBUG) {
550                 Slog.e(LOG_TAG, "Error findAccessibilityNodeInfoByViewId().");
551             }
552         } finally {
553             Binder.restoreCallingIdentity(identityToken);
554             // Recycle if passed to another process.
555             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
556                 partialInteractiveRegion.recycle();
557             }
558         }
559         return null;
560     }
561 
562     @Override
findAccessibilityNodeInfosByText(int accessibilityWindowId, long accessibilityNodeId, String text, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)563     public String[] findAccessibilityNodeInfosByText(int accessibilityWindowId,
564             long accessibilityNodeId, String text, int interactionId,
565             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
566             throws RemoteException {
567         if (mTrace.isA11yTracingEnabled()) {
568             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfosByText",
569                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
570                     + accessibilityNodeId + ";text=" + text + ";interactionId=" + interactionId
571                     + ";callback=" + callback + ";interrogatingTid=" + interrogatingTid);
572         }
573         final int resolvedWindowId;
574         RemoteAccessibilityConnection connection;
575         Region partialInteractiveRegion = Region.obtain();
576         MagnificationSpec spec;
577         synchronized (mLock) {
578             mUsesAccessibilityCache = true;
579             if (!hasRightsToCurrentUserLocked()) {
580                 return null;
581             }
582             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
583             final boolean permissionGranted =
584                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
585                             mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId);
586             if (!permissionGranted) {
587                 return null;
588             } else {
589                 connection = mA11yWindowManager.getConnectionLocked(
590                         mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId);
591                 if (connection == null) {
592                     return null;
593                 }
594             }
595             if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
596                     resolvedWindowId, partialInteractiveRegion)) {
597                 partialInteractiveRegion.recycle();
598                 partialInteractiveRegion = null;
599             }
600             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
601         }
602         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
603             return null;
604         }
605         final int interrogatingPid = Binder.getCallingPid();
606         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
607                 interrogatingPid, interrogatingTid);
608         final long identityToken = Binder.clearCallingIdentity();
609         try {
610             connection.getRemote().findAccessibilityNodeInfosByText(accessibilityNodeId,
611                     text, partialInteractiveRegion, interactionId, callback, mFetchFlags,
612                     interrogatingPid, interrogatingTid, spec);
613             return mSecurityPolicy.computeValidReportedPackages(
614                     connection.getPackageName(), connection.getUid());
615         } catch (RemoteException re) {
616             if (DEBUG) {
617                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfosByText()");
618             }
619         } finally {
620             Binder.restoreCallingIdentity(identityToken);
621             // Recycle if passed to another process.
622             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
623                 partialInteractiveRegion.recycle();
624             }
625         }
626         return null;
627     }
628 
629     @Override
findAccessibilityNodeInfoByAccessibilityId( int accessibilityWindowId, long accessibilityNodeId, int interactionId, IAccessibilityInteractionConnectionCallback callback, int flags, long interrogatingTid, Bundle arguments)630     public String[] findAccessibilityNodeInfoByAccessibilityId(
631             int accessibilityWindowId, long accessibilityNodeId, int interactionId,
632             IAccessibilityInteractionConnectionCallback callback, int flags,
633             long interrogatingTid, Bundle arguments) throws RemoteException {
634         if (mTrace.isA11yTracingEnabled()) {
635             mTrace.logTrace(
636                     TRACE_A11Y_SERVICE_CONNECTION + ".findAccessibilityNodeInfoByAccessibilityId",
637                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
638                             + accessibilityNodeId + ";interactionId=" + interactionId + ";callback="
639                             + callback + ";flags=" + flags + ";interrogatingTid=" + interrogatingTid
640                             + ";arguments=" + arguments);
641         }
642         final int resolvedWindowId;
643         RemoteAccessibilityConnection connection;
644         Region partialInteractiveRegion = Region.obtain();
645         MagnificationSpec spec;
646         synchronized (mLock) {
647             mUsesAccessibilityCache = true;
648             if (!hasRightsToCurrentUserLocked()) {
649                 return null;
650             }
651             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
652             final boolean permissionGranted =
653                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
654                             mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId);
655             if (!permissionGranted) {
656                 return null;
657             } else {
658                 connection = mA11yWindowManager.getConnectionLocked(
659                         mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId);
660                 if (connection == null) {
661                     return null;
662                 }
663             }
664             if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
665                     resolvedWindowId, partialInteractiveRegion)) {
666                 partialInteractiveRegion.recycle();
667                 partialInteractiveRegion = null;
668             }
669             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
670         }
671         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
672             return null;
673         }
674         final int interrogatingPid = Binder.getCallingPid();
675         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
676                 interrogatingPid, interrogatingTid);
677         final long identityToken = Binder.clearCallingIdentity();
678         try {
679             connection.getRemote().findAccessibilityNodeInfoByAccessibilityId(
680                     accessibilityNodeId, partialInteractiveRegion, interactionId, callback,
681                     mFetchFlags | flags, interrogatingPid, interrogatingTid, spec, arguments);
682             return mSecurityPolicy.computeValidReportedPackages(
683                     connection.getPackageName(), connection.getUid());
684         } catch (RemoteException re) {
685             if (DEBUG) {
686                 Slog.e(LOG_TAG, "Error calling findAccessibilityNodeInfoByAccessibilityId()");
687             }
688         } finally {
689             Binder.restoreCallingIdentity(identityToken);
690             // Recycle if passed to another process.
691             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
692                 partialInteractiveRegion.recycle();
693             }
694         }
695         return null;
696     }
697 
698     @Override
findFocus(int accessibilityWindowId, long accessibilityNodeId, int focusType, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)699     public String[] findFocus(int accessibilityWindowId, long accessibilityNodeId,
700             int focusType, int interactionId,
701             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
702             throws RemoteException {
703         if (mTrace.isA11yTracingEnabled()) {
704             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".findFocus",
705                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
706                             + accessibilityNodeId + ";focusType=" + focusType + ";interactionId="
707                             + interactionId + ";callback=" + callback + ";interrogatingTid="
708                             + interrogatingTid);
709         }
710         final int resolvedWindowId;
711         RemoteAccessibilityConnection connection;
712         Region partialInteractiveRegion = Region.obtain();
713         MagnificationSpec spec;
714         synchronized (mLock) {
715             if (!hasRightsToCurrentUserLocked()) {
716                 return null;
717             }
718             resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
719                     accessibilityWindowId, focusType);
720             final boolean permissionGranted =
721                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
722                             mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId);
723             if (!permissionGranted) {
724                 return null;
725             } else {
726                 connection = mA11yWindowManager.getConnectionLocked(
727                         mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId);
728                 if (connection == null) {
729                     return null;
730                 }
731             }
732             if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
733                     resolvedWindowId, partialInteractiveRegion)) {
734                 partialInteractiveRegion.recycle();
735                 partialInteractiveRegion = null;
736             }
737             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
738         }
739         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
740             return null;
741         }
742         final int interrogatingPid = Binder.getCallingPid();
743         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
744                 interrogatingPid, interrogatingTid);
745         final long identityToken = Binder.clearCallingIdentity();
746         try {
747             connection.getRemote().findFocus(accessibilityNodeId, focusType,
748                     partialInteractiveRegion, interactionId, callback, mFetchFlags,
749                     interrogatingPid, interrogatingTid, spec);
750             return mSecurityPolicy.computeValidReportedPackages(
751                     connection.getPackageName(), connection.getUid());
752         } catch (RemoteException re) {
753             if (DEBUG) {
754                 Slog.e(LOG_TAG, "Error calling findFocus()");
755             }
756         } finally {
757             Binder.restoreCallingIdentity(identityToken);
758             // Recycle if passed to another process.
759             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
760                 partialInteractiveRegion.recycle();
761             }
762         }
763         return null;
764     }
765 
766     @Override
focusSearch(int accessibilityWindowId, long accessibilityNodeId, int direction, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)767     public String[] focusSearch(int accessibilityWindowId, long accessibilityNodeId,
768             int direction, int interactionId,
769             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
770             throws RemoteException {
771         if (mTrace.isA11yTracingEnabled()) {
772             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".focusSearch",
773                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
774                             + accessibilityNodeId + ";direction=" + direction + ";interactionId="
775                             + interactionId + ";callback=" + callback + ";interrogatingTid="
776                             + interrogatingTid);
777         }
778         final int resolvedWindowId;
779         RemoteAccessibilityConnection connection;
780         Region partialInteractiveRegion = Region.obtain();
781         MagnificationSpec spec;
782         synchronized (mLock) {
783             if (!hasRightsToCurrentUserLocked()) {
784                 return null;
785             }
786             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
787             final boolean permissionGranted =
788                     mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
789                             mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId);
790             if (!permissionGranted) {
791                 return null;
792             } else {
793                 connection = mA11yWindowManager.getConnectionLocked(
794                         mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId);
795                 if (connection == null) {
796                     return null;
797                 }
798             }
799             if (!mA11yWindowManager.computePartialInteractiveRegionForWindowLocked(
800                     resolvedWindowId, partialInteractiveRegion)) {
801                 partialInteractiveRegion.recycle();
802                 partialInteractiveRegion = null;
803             }
804             spec = mSystemSupport.getCompatibleMagnificationSpecLocked(resolvedWindowId);
805         }
806         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
807             return null;
808         }
809         final int interrogatingPid = Binder.getCallingPid();
810         callback = replaceCallbackIfNeeded(callback, resolvedWindowId, interactionId,
811                 interrogatingPid, interrogatingTid);
812         final long identityToken = Binder.clearCallingIdentity();
813         try {
814             connection.getRemote().focusSearch(accessibilityNodeId, direction,
815                     partialInteractiveRegion, interactionId, callback, mFetchFlags,
816                     interrogatingPid, interrogatingTid, spec);
817             return mSecurityPolicy.computeValidReportedPackages(
818                     connection.getPackageName(), connection.getUid());
819         } catch (RemoteException re) {
820             if (DEBUG) {
821                 Slog.e(LOG_TAG, "Error calling accessibilityFocusSearch()");
822             }
823         } finally {
824             Binder.restoreCallingIdentity(identityToken);
825             // Recycle if passed to another process.
826             if (partialInteractiveRegion != null && Binder.isProxy(connection.getRemote())) {
827                 partialInteractiveRegion.recycle();
828             }
829         }
830         return null;
831     }
832 
833     @Override
sendGesture(int sequence, ParceledListSlice gestureSteps)834     public void sendGesture(int sequence, ParceledListSlice gestureSteps) {
835         if (mTrace.isA11yTracingEnabled()) {
836             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".sendGesture",
837                     "sequence=" + sequence + ";gestureSteps=" + gestureSteps);
838         }
839     }
840 
841     @Override
dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId)842     public void dispatchGesture(int sequence, ParceledListSlice gestureSteps, int displayId) {
843         if (mTrace.isA11yTracingEnabled()) {
844             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".dispatchGesture", "sequence="
845                     + sequence + ";gestureSteps=" + gestureSteps + ";displayId=" + displayId);
846         }
847     }
848 
849     @Override
performAccessibilityAction(int accessibilityWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)850     public boolean performAccessibilityAction(int accessibilityWindowId,
851             long accessibilityNodeId, int action, Bundle arguments, int interactionId,
852             IAccessibilityInteractionConnectionCallback callback, long interrogatingTid)
853             throws RemoteException {
854         if (mTrace.isA11yTracingEnabled()) {
855             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".performAccessibilityAction",
856                     "accessibilityWindowId=" + accessibilityWindowId + ";accessibilityNodeId="
857                             + accessibilityNodeId + ";action=" + action + ";arguments=" + arguments
858                             + ";interactionId=" + interactionId + ";callback=" + callback
859                             + ";interrogatingTid=" + interrogatingTid);
860         }
861         final int resolvedWindowId;
862         synchronized (mLock) {
863             if (!hasRightsToCurrentUserLocked()) {
864                 return false;
865             }
866             resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
867             if (!mSecurityPolicy.canGetAccessibilityNodeInfoLocked(
868                     mSystemSupport.getCurrentUserIdLocked(), this, resolvedWindowId)) {
869                 return false;
870             }
871         }
872         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
873             return false;
874         }
875         return performAccessibilityActionInternal(
876                 mSystemSupport.getCurrentUserIdLocked(), resolvedWindowId, accessibilityNodeId,
877                 action, arguments, interactionId, callback, mFetchFlags, interrogatingTid);
878     }
879 
880     @Override
performGlobalAction(int action)881     public boolean performGlobalAction(int action) {
882         if (mTrace.isA11yTracingEnabled()) {
883             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".performGlobalAction",
884                     "action=" + action);
885         }
886         synchronized (mLock) {
887             if (!hasRightsToCurrentUserLocked()) {
888                 return false;
889             }
890         }
891         return mSystemActionPerformer.performSystemAction(action);
892     }
893 
894     @Override
getSystemActions()895     public @NonNull List<AccessibilityNodeInfo.AccessibilityAction> getSystemActions() {
896         if (mTrace.isA11yTracingEnabled()) {
897             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getSystemActions");
898         }
899         synchronized (mLock) {
900             if (!hasRightsToCurrentUserLocked()) {
901                 return Collections.emptyList();
902             }
903         }
904         return mSystemActionPerformer.getSystemActions();
905     }
906 
907     @Override
isFingerprintGestureDetectionAvailable()908     public boolean isFingerprintGestureDetectionAvailable() {
909         if (mTrace.isA11yTracingEnabled()) {
910             mTrace.logTrace(
911                     TRACE_A11Y_SERVICE_CONNECTION + ".isFingerprintGestureDetectionAvailable");
912         }
913         if (!mContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
914             return false;
915         }
916         if (isCapturingFingerprintGestures()) {
917             FingerprintGestureDispatcher dispatcher =
918                     mSystemSupport.getFingerprintGestureDispatcher();
919             return (dispatcher != null) && dispatcher.isFingerprintGestureDetectionAvailable();
920         }
921         return false;
922     }
923 
924     @Override
getMagnificationScale(int displayId)925     public float getMagnificationScale(int displayId) {
926         if (mTrace.isA11yTracingEnabled()) {
927             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationScale",
928                     "displayId=" + displayId);
929         }
930         synchronized (mLock) {
931             if (!hasRightsToCurrentUserLocked()) {
932                 return 1.0f;
933             }
934         }
935         final long identity = Binder.clearCallingIdentity();
936         try {
937             return mSystemSupport.getFullScreenMagnificationController().getScale(displayId);
938         } finally {
939             Binder.restoreCallingIdentity(identity);
940         }
941     }
942 
943     @Override
getMagnificationRegion(int displayId)944     public Region getMagnificationRegion(int displayId) {
945         if (mTrace.isA11yTracingEnabled()) {
946             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationRegion",
947                     "displayId=" + displayId);
948         }
949         synchronized (mLock) {
950             final Region region = Region.obtain();
951             if (!hasRightsToCurrentUserLocked()) {
952                 return region;
953             }
954             FullScreenMagnificationController magnificationController =
955                     mSystemSupport.getFullScreenMagnificationController();
956             boolean registeredJustForThisCall =
957                     registerMagnificationIfNeeded(displayId, magnificationController);
958             final long identity = Binder.clearCallingIdentity();
959             try {
960                 magnificationController.getMagnificationRegion(displayId, region);
961                 return region;
962             } finally {
963                 Binder.restoreCallingIdentity(identity);
964                 if (registeredJustForThisCall) {
965                     magnificationController.unregister(displayId);
966                 }
967             }
968         }
969     }
970 
971     @Override
getMagnificationCenterX(int displayId)972     public float getMagnificationCenterX(int displayId) {
973         if (mTrace.isA11yTracingEnabled()) {
974             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationCenterX",
975                     "displayId=" + displayId);
976         }
977         synchronized (mLock) {
978             if (!hasRightsToCurrentUserLocked()) {
979                 return 0.0f;
980             }
981             FullScreenMagnificationController magnificationController =
982                     mSystemSupport.getFullScreenMagnificationController();
983             boolean registeredJustForThisCall =
984                     registerMagnificationIfNeeded(displayId, magnificationController);
985             final long identity = Binder.clearCallingIdentity();
986             try {
987                 return magnificationController.getCenterX(displayId);
988             } finally {
989                 Binder.restoreCallingIdentity(identity);
990                 if (registeredJustForThisCall) {
991                     magnificationController.unregister(displayId);
992                 }
993             }
994         }
995     }
996 
997     @Override
getMagnificationCenterY(int displayId)998     public float getMagnificationCenterY(int displayId) {
999         if (mTrace.isA11yTracingEnabled()) {
1000             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getMagnificationCenterY",
1001                     "displayId=" + displayId);
1002         }
1003         synchronized (mLock) {
1004             if (!hasRightsToCurrentUserLocked()) {
1005                 return 0.0f;
1006             }
1007             FullScreenMagnificationController magnificationController =
1008                     mSystemSupport.getFullScreenMagnificationController();
1009             boolean registeredJustForThisCall =
1010                     registerMagnificationIfNeeded(displayId, magnificationController);
1011             final long identity = Binder.clearCallingIdentity();
1012             try {
1013                 return magnificationController.getCenterY(displayId);
1014             } finally {
1015                 Binder.restoreCallingIdentity(identity);
1016                 if (registeredJustForThisCall) {
1017                     magnificationController.unregister(displayId);
1018                 }
1019             }
1020         }
1021     }
1022 
registerMagnificationIfNeeded(int displayId, FullScreenMagnificationController magnificationController)1023     private boolean registerMagnificationIfNeeded(int displayId,
1024             FullScreenMagnificationController magnificationController) {
1025         if (!magnificationController.isRegistered(displayId)
1026                 && mSecurityPolicy.canControlMagnification(this)) {
1027             magnificationController.register(displayId);
1028             return true;
1029         }
1030         return false;
1031     }
1032 
1033     @Override
resetMagnification(int displayId, boolean animate)1034     public boolean resetMagnification(int displayId, boolean animate) {
1035         if (mTrace.isA11yTracingEnabled()) {
1036             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".resetMagnification",
1037                     "displayId=" + displayId + ";animate=" + animate);
1038         }
1039         synchronized (mLock) {
1040             if (!hasRightsToCurrentUserLocked()) {
1041                 return false;
1042             }
1043             if (!mSecurityPolicy.canControlMagnification(this)) {
1044                 return false;
1045             }
1046         }
1047         final long identity = Binder.clearCallingIdentity();
1048         try {
1049             FullScreenMagnificationController magnificationController =
1050                     mSystemSupport.getFullScreenMagnificationController();
1051             return (magnificationController.reset(displayId, animate)
1052                     || !magnificationController.isMagnifying(displayId));
1053         } finally {
1054             Binder.restoreCallingIdentity(identity);
1055         }
1056     }
1057 
1058     @Override
setMagnificationScaleAndCenter(int displayId, float scale, float centerX, float centerY, boolean animate)1059     public boolean setMagnificationScaleAndCenter(int displayId, float scale, float centerX,
1060             float centerY, boolean animate) {
1061         if (mTrace.isA11yTracingEnabled()) {
1062             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setMagnificationScaleAndCenter",
1063                     "displayId=" + displayId + ";scale=" + scale + ";centerX=" + centerX
1064                             + ";centerY=" + centerY + ";animate=" + animate);
1065         }
1066         synchronized (mLock) {
1067             if (!hasRightsToCurrentUserLocked()) {
1068                 return false;
1069             }
1070             if (!mSecurityPolicy.canControlMagnification(this)) {
1071                 return false;
1072             }
1073             final long identity = Binder.clearCallingIdentity();
1074             try {
1075                 FullScreenMagnificationController magnificationController =
1076                         mSystemSupport.getFullScreenMagnificationController();
1077                 if (!magnificationController.isRegistered(displayId)) {
1078                     magnificationController.register(displayId);
1079                 }
1080                 return magnificationController
1081                         .setScaleAndCenter(displayId, scale, centerX, centerY, animate, mId);
1082             } finally {
1083                 Binder.restoreCallingIdentity(identity);
1084             }
1085         }
1086     }
1087 
1088     @Override
setMagnificationCallbackEnabled(int displayId, boolean enabled)1089     public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {
1090         if (mTrace.isA11yTracingEnabled()) {
1091             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setMagnificationCallbackEnabled",
1092                     "displayId=" + displayId + ";enabled=" + enabled);
1093         }
1094         mInvocationHandler.setMagnificationCallbackEnabled(displayId, enabled);
1095     }
1096 
isMagnificationCallbackEnabled(int displayId)1097     public boolean isMagnificationCallbackEnabled(int displayId) {
1098         return mInvocationHandler.isMagnificationCallbackEnabled(displayId);
1099     }
1100 
1101     @Override
setSoftKeyboardCallbackEnabled(boolean enabled)1102     public void setSoftKeyboardCallbackEnabled(boolean enabled) {
1103         if (mTrace.isA11yTracingEnabled()) {
1104             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setSoftKeyboardCallbackEnabled",
1105                     "enabled=" + enabled);
1106         }
1107         mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
1108     }
1109 
1110     @Override
takeScreenshot(int displayId, RemoteCallback callback)1111     public void takeScreenshot(int displayId, RemoteCallback callback) {
1112         if (mTrace.isA11yTracingEnabled()) {
1113             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".takeScreenshot",
1114                     "displayId=" + displayId + ";callback=" + callback);
1115         }
1116         final long currentTimestamp = SystemClock.uptimeMillis();
1117         if (mRequestTakeScreenshotTimestampMs != 0
1118                 && (currentTimestamp - mRequestTakeScreenshotTimestampMs)
1119                 <= AccessibilityService.ACCESSIBILITY_TAKE_SCREENSHOT_REQUEST_INTERVAL_TIMES_MS) {
1120             sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERVAL_TIME_SHORT,
1121                     callback);
1122             return;
1123         }
1124         mRequestTakeScreenshotTimestampMs = currentTimestamp;
1125 
1126         synchronized (mLock) {
1127             if (!hasRightsToCurrentUserLocked()) {
1128                 sendScreenshotFailure(AccessibilityService.ERROR_TAKE_SCREENSHOT_INTERNAL_ERROR,
1129                         callback);
1130                 return;
1131             }
1132 
1133             if (!mSecurityPolicy.canTakeScreenshotLocked(this)) {
1134                 throw new SecurityException("Services don't have the capability of taking"
1135                         + " the screenshot.");
1136             }
1137         }
1138 
1139         if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
1140             sendScreenshotFailure(
1141                     AccessibilityService.ERROR_TAKE_SCREENSHOT_NO_ACCESSIBILITY_ACCESS,
1142                     callback);
1143             return;
1144         }
1145 
1146         // Private virtual displays are created by the ap and is not allowed to access by other
1147         // aps.  We assume the contents on this display should not be captured.
1148         final DisplayManager displayManager =
1149                 (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
1150         final Display display = displayManager.getDisplay(displayId);
1151         if ((display == null) || (display.getType() == Display.TYPE_VIRTUAL
1152                 && (display.getFlags() & Display.FLAG_PRIVATE) != 0)) {
1153             sendScreenshotFailure(
1154                     AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback);
1155             return;
1156         }
1157 
1158         final long identity = Binder.clearCallingIdentity();
1159         try {
1160             mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
1161                 final ScreenshotHardwareBuffer screenshotBuffer = LocalServices
1162                         .getService(DisplayManagerInternal.class).userScreenshot(displayId);
1163                 if (screenshotBuffer != null) {
1164                     sendScreenshotSuccess(screenshotBuffer, callback);
1165                 } else {
1166                     sendScreenshotFailure(
1167                             AccessibilityService.ERROR_TAKE_SCREENSHOT_INVALID_DISPLAY, callback);
1168                 }
1169             }, null).recycleOnUse());
1170         } finally {
1171             Binder.restoreCallingIdentity(identity);
1172         }
1173     }
1174 
sendScreenshotSuccess(ScreenshotHardwareBuffer screenshotBuffer, RemoteCallback callback)1175     private void sendScreenshotSuccess(ScreenshotHardwareBuffer screenshotBuffer,
1176             RemoteCallback callback) {
1177         final HardwareBuffer hardwareBuffer = screenshotBuffer.getHardwareBuffer();
1178         final ParcelableColorSpace colorSpace =
1179                 new ParcelableColorSpace(screenshotBuffer.getColorSpace());
1180 
1181         final Bundle payload = new Bundle();
1182         payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS,
1183                 AccessibilityService.TAKE_SCREENSHOT_SUCCESS);
1184         payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_HARDWAREBUFFER,
1185                 hardwareBuffer);
1186         payload.putParcelable(KEY_ACCESSIBILITY_SCREENSHOT_COLORSPACE, colorSpace);
1187         payload.putLong(KEY_ACCESSIBILITY_SCREENSHOT_TIMESTAMP,
1188                 SystemClock.uptimeMillis());
1189 
1190         // Send back the result.
1191         callback.sendResult(payload);
1192         hardwareBuffer.close();
1193     }
1194 
sendScreenshotFailure(@ccessibilityService.ScreenshotErrorCode int errorCode, RemoteCallback callback)1195     private void sendScreenshotFailure(@AccessibilityService.ScreenshotErrorCode int errorCode,
1196             RemoteCallback callback) {
1197         mMainHandler.post(PooledLambda.obtainRunnable((nonArg) -> {
1198             final Bundle payload = new Bundle();
1199             payload.putInt(KEY_ACCESSIBILITY_SCREENSHOT_STATUS, errorCode);
1200             // Send back the result.
1201             callback.sendResult(payload);
1202         }, null).recycleOnUse());
1203     }
1204 
1205     @Override
dump(FileDescriptor fd, final PrintWriter pw, String[] args)1206     public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
1207         if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;
1208         synchronized (mLock) {
1209             pw.append("Service[label=" + mAccessibilityServiceInfo.getResolveInfo()
1210                     .loadLabel(mContext.getPackageManager()));
1211             pw.append(", feedbackType"
1212                     + AccessibilityServiceInfo.feedbackTypeToString(mFeedbackType));
1213             pw.append(", capabilities=" + mAccessibilityServiceInfo.getCapabilities());
1214             pw.append(", eventTypes="
1215                     + AccessibilityEvent.eventTypeToString(mEventTypes));
1216             pw.append(", notificationTimeout=" + mNotificationTimeout);
1217             pw.append(", requestA11yBtn=" + mRequestAccessibilityButton);
1218             pw.append("]");
1219         }
1220     }
1221 
onAdded()1222     public void onAdded() {
1223         final Display[] displays = mDisplayManager.getDisplays();
1224         for (int i = 0; i < displays.length; i++) {
1225             final int displayId = displays[i].getDisplayId();
1226             onDisplayAdded(displayId);
1227         }
1228     }
1229 
1230     /**
1231      * Called whenever a logical display has been added to the system. Add a window token for adding
1232      * an accessibility overlay.
1233      *
1234      * @param displayId The id of the logical display that was added.
1235      */
onDisplayAdded(int displayId)1236     public void onDisplayAdded(int displayId) {
1237         final long identity = Binder.clearCallingIdentity();
1238         try {
1239             final IBinder overlayWindowToken = new Binder();
1240             mWindowManagerService.addWindowToken(overlayWindowToken, TYPE_ACCESSIBILITY_OVERLAY,
1241                     displayId, null /* options */);
1242             synchronized (mLock) {
1243                 mOverlayWindowTokens.put(displayId, overlayWindowToken);
1244             }
1245         } finally {
1246             Binder.restoreCallingIdentity(identity);
1247         }
1248     }
1249 
onRemoved()1250     public void onRemoved() {
1251         final Display[] displays = mDisplayManager.getDisplays();
1252         for (int i = 0; i < displays.length; i++) {
1253             final int displayId = displays[i].getDisplayId();
1254             onDisplayRemoved(displayId);
1255         }
1256     }
1257 
1258     /**
1259      * Called whenever a logical display has been removed from the system. Remove a window token for
1260      * removing an accessibility overlay.
1261      *
1262      * @param displayId The id of the logical display that was added.
1263      */
onDisplayRemoved(int displayId)1264     public void onDisplayRemoved(int displayId) {
1265         final long identity = Binder.clearCallingIdentity();
1266         try {
1267             mWindowManagerService.removeWindowToken(mOverlayWindowTokens.get(displayId), true,
1268                     displayId);
1269             synchronized (mLock) {
1270                 mOverlayWindowTokens.remove(displayId);
1271             }
1272         } finally {
1273             Binder.restoreCallingIdentity(identity);
1274         }
1275     }
1276 
1277     /**
1278      * Gets overlay window token by the display Id.
1279      *
1280      * @param displayId The id of the logical display that was added.
1281      * @return window token.
1282      */
1283     @Override
getOverlayWindowToken(int displayId)1284     public IBinder getOverlayWindowToken(int displayId) {
1285         if (mTrace.isA11yTracingEnabled()) {
1286             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getOverlayWindowToken",
1287                     "displayId=" + displayId);
1288         }
1289         synchronized (mLock) {
1290             return mOverlayWindowTokens.get(displayId);
1291         }
1292     }
1293 
1294     /**
1295      * Gets windowId of given token.
1296      *
1297      * @param token The token
1298      * @return window id
1299      */
1300     @Override
getWindowIdForLeashToken(@onNull IBinder token)1301     public int getWindowIdForLeashToken(@NonNull IBinder token) {
1302         if (mTrace.isA11yTracingEnabled()) {
1303             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".getWindowIdForLeashToken",
1304                     "token=" + token);
1305         }
1306         synchronized (mLock) {
1307             return mA11yWindowManager.getWindowIdLocked(token);
1308         }
1309     }
1310 
resetLocked()1311     public void resetLocked() {
1312         mSystemSupport.getKeyEventDispatcher().flush(this);
1313         try {
1314             // Clear the proxy in the other process so this
1315             // IAccessibilityServiceConnection can be garbage collected.
1316             if (mServiceInterface != null) {
1317                 if (mTrace.isA11yTracingEnabled()) {
1318                     mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".init", "null, " + mId + ", null");
1319                 }
1320                 mServiceInterface.init(null, mId, null);
1321             }
1322         } catch (RemoteException re) {
1323                 /* ignore */
1324         }
1325         if (mService != null) {
1326             try {
1327                 mService.unlinkToDeath(this, 0);
1328             } catch (NoSuchElementException e) {
1329                 Slog.e(LOG_TAG, "Failed unregistering death link");
1330             }
1331             mService = null;
1332         }
1333 
1334         mServiceInterface = null;
1335         mReceivedAccessibilityButtonCallbackSinceBind = false;
1336     }
1337 
isConnectedLocked()1338     public boolean isConnectedLocked() {
1339         return (mService != null);
1340     }
1341 
notifyAccessibilityEvent(AccessibilityEvent event)1342     public void notifyAccessibilityEvent(AccessibilityEvent event) {
1343         synchronized (mLock) {
1344             final int eventType = event.getEventType();
1345 
1346             final boolean serviceWantsEvent = wantsEventLocked(event);
1347             final boolean requiredForCacheConsistency = mUsesAccessibilityCache
1348                     && ((AccessibilityCache.CACHE_CRITICAL_EVENTS_MASK & eventType) != 0);
1349             if (!serviceWantsEvent && !requiredForCacheConsistency) {
1350                 return;
1351             }
1352 
1353             if (!mSecurityPolicy.checkAccessibilityAccess(this)) {
1354                 return;
1355             }
1356             // Make a copy since during dispatch it is possible the event to
1357             // be modified to remove its source if the receiving service does
1358             // not have permission to access the window content.
1359             AccessibilityEvent newEvent = AccessibilityEvent.obtain(event);
1360             Message message;
1361             if ((mNotificationTimeout > 0)
1362                     && (eventType != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED)) {
1363                 // Allow at most one pending event
1364                 final AccessibilityEvent oldEvent = mPendingEvents.get(eventType);
1365                 mPendingEvents.put(eventType, newEvent);
1366                 if (oldEvent != null) {
1367                     mEventDispatchHandler.removeMessages(eventType);
1368                     oldEvent.recycle();
1369                 }
1370                 message = mEventDispatchHandler.obtainMessage(eventType);
1371             } else {
1372                 // Send all messages, bypassing mPendingEvents
1373                 message = mEventDispatchHandler.obtainMessage(eventType, newEvent);
1374             }
1375             message.arg1 = serviceWantsEvent ? 1 : 0;
1376 
1377             mEventDispatchHandler.sendMessageDelayed(message, mNotificationTimeout);
1378         }
1379     }
1380 
1381     /**
1382      * Determines if given event can be dispatched to a service based on the package of the
1383      * event source. Specifically, a service is notified if it is interested in events from the
1384      * package.
1385      *
1386      * @param event The event.
1387      * @return True if the listener should be notified, false otherwise.
1388      */
wantsEventLocked(AccessibilityEvent event)1389     private boolean wantsEventLocked(AccessibilityEvent event) {
1390 
1391         if (!canReceiveEventsLocked()) {
1392             return false;
1393         }
1394 
1395         if ((event.getWindowId() != AccessibilityWindowInfo.UNDEFINED_WINDOW_ID)
1396                 && !event.isImportantForAccessibility()
1397                 && (mFetchFlags & AccessibilityNodeInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS) == 0) {
1398             return false;
1399         }
1400 
1401         int eventType = event.getEventType();
1402         if ((mEventTypes & eventType) != eventType) {
1403             return false;
1404         }
1405 
1406         Set<String> packageNames = mPackageNames;
1407         String packageName = (event.getPackageName() != null)
1408                 ? event.getPackageName().toString() : null;
1409 
1410         return (packageNames.isEmpty() || packageNames.contains(packageName));
1411     }
1412 
1413     /**
1414      * Notifies an accessibility service client for a scheduled event given the event type.
1415      *
1416      * @param eventType The type of the event to dispatch.
1417      */
notifyAccessibilityEventInternal( int eventType, AccessibilityEvent event, boolean serviceWantsEvent)1418     private void notifyAccessibilityEventInternal(
1419             int eventType,
1420             AccessibilityEvent event,
1421             boolean serviceWantsEvent) {
1422         IAccessibilityServiceClient listener;
1423 
1424         synchronized (mLock) {
1425             listener = mServiceInterface;
1426 
1427             // If the service died/was disabled while the message for dispatching
1428             // the accessibility event was propagating the listener may be null.
1429             if (listener == null) {
1430                 return;
1431             }
1432 
1433             // There are two ways we notify for events, throttled AND non-throttled. If we
1434             // are not throttling, then messages come with events, which we handle with
1435             // minimal fuss.
1436             if (event == null) {
1437                 // We are throttling events, so we'll send the event for this type in
1438                 // mPendingEvents as long as it it's null. It can only null due to a race
1439                 // condition:
1440                 //
1441                 //   1) A binder thread calls notifyAccessibilityServiceDelayedLocked
1442                 //      which posts a message for dispatching an event and stores the event
1443                 //      in mPendingEvents.
1444                 //   2) The message is pulled from the queue by the handler on the service
1445                 //      thread and this method is just about to acquire the lock.
1446                 //   3) Another binder thread acquires the lock in notifyAccessibilityEvent
1447                 //   4) notifyAccessibilityEvent recycles the event that this method was about
1448                 //      to process, replaces it with a new one, and posts a second message
1449                 //   5) This method grabs the new event, processes it, and removes it from
1450                 //      mPendingEvents
1451                 //   6) The second message dispatched in (4) arrives, but the event has been
1452                 //      remvoved in (5).
1453                 event = mPendingEvents.get(eventType);
1454                 if (event == null) {
1455                     return;
1456                 }
1457                 mPendingEvents.remove(eventType);
1458             }
1459             if (mSecurityPolicy.canRetrieveWindowContentLocked(this)) {
1460                 event.setConnectionId(mId);
1461             } else {
1462                 event.setSource((View) null);
1463             }
1464             event.setSealed(true);
1465         }
1466 
1467         try {
1468             if (mTrace.isA11yTracingEnabled()) {
1469                 mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityEvent",
1470                         event + ";" + serviceWantsEvent);
1471             }
1472             listener.onAccessibilityEvent(event, serviceWantsEvent);
1473             if (DEBUG) {
1474                 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener);
1475             }
1476         } catch (RemoteException re) {
1477             Slog.e(LOG_TAG, "Error during sending " + event + " to " + listener, re);
1478         } finally {
1479             event.recycle();
1480         }
1481     }
1482 
notifyGesture(AccessibilityGestureEvent gestureEvent)1483     public void notifyGesture(AccessibilityGestureEvent gestureEvent) {
1484         mInvocationHandler.obtainMessage(InvocationHandler.MSG_ON_GESTURE,
1485                 gestureEvent).sendToTarget();
1486     }
1487 
notifySystemActionsChangedLocked()1488     public void notifySystemActionsChangedLocked() {
1489         mInvocationHandler.sendEmptyMessage(
1490                 InvocationHandler.MSG_ON_SYSTEM_ACTIONS_CHANGED);
1491     }
1492 
notifyClearAccessibilityNodeInfoCache()1493     public void notifyClearAccessibilityNodeInfoCache() {
1494         mInvocationHandler.sendEmptyMessage(
1495                 InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
1496     }
1497 
notifyMagnificationChangedLocked(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1498     public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region,
1499             float scale, float centerX, float centerY) {
1500         mInvocationHandler
1501                 .notifyMagnificationChangedLocked(displayId, region, scale, centerX, centerY);
1502     }
1503 
notifySoftKeyboardShowModeChangedLocked(int showState)1504     public void notifySoftKeyboardShowModeChangedLocked(int showState) {
1505         mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState);
1506     }
1507 
notifyAccessibilityButtonClickedLocked(int displayId)1508     public void notifyAccessibilityButtonClickedLocked(int displayId) {
1509         mInvocationHandler.notifyAccessibilityButtonClickedLocked(displayId);
1510     }
1511 
notifyAccessibilityButtonAvailabilityChangedLocked(boolean available)1512     public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
1513         mInvocationHandler.notifyAccessibilityButtonAvailabilityChangedLocked(available);
1514     }
1515 
1516     /**
1517      * Called by the invocation handler to notify the service that the
1518      * state of magnification has changed.
1519      */
notifyMagnificationChangedInternal(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1520     private void notifyMagnificationChangedInternal(int displayId, @NonNull Region region,
1521             float scale, float centerX, float centerY) {
1522         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1523         if (listener != null) {
1524             try {
1525                 if (mTrace.isA11yTracingEnabled()) {
1526                     mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onMagnificationChanged", displayId
1527                             + ", " + region + ", " + scale + ", " + centerX + ", " + centerY);
1528                 }
1529                 listener.onMagnificationChanged(displayId, region, scale, centerX, centerY);
1530             } catch (RemoteException re) {
1531                 Slog.e(LOG_TAG, "Error sending magnification changes to " + mService, re);
1532             }
1533         }
1534     }
1535 
1536     /**
1537      * Called by the invocation handler to notify the service that the state of the soft
1538      * keyboard show mode has changed.
1539      */
notifySoftKeyboardShowModeChangedInternal(int showState)1540     private void notifySoftKeyboardShowModeChangedInternal(int showState) {
1541         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1542         if (listener != null) {
1543             try {
1544                 if (mTrace.isA11yTracingEnabled()) {
1545                     mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onSoftKeyboardShowModeChanged",
1546                             String.valueOf(showState));
1547                 }
1548                 listener.onSoftKeyboardShowModeChanged(showState);
1549             } catch (RemoteException re) {
1550                 Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService,
1551                         re);
1552             }
1553         }
1554     }
1555 
notifyAccessibilityButtonClickedInternal(int displayId)1556     private void notifyAccessibilityButtonClickedInternal(int displayId) {
1557         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1558         if (listener != null) {
1559             try {
1560                 if (mTrace.isA11yTracingEnabled()) {
1561                     mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityButtonClicked",
1562                             String.valueOf(displayId));
1563                 }
1564                 listener.onAccessibilityButtonClicked(displayId);
1565             } catch (RemoteException re) {
1566                 Slog.e(LOG_TAG, "Error sending accessibility button click to " + mService, re);
1567             }
1568         }
1569     }
1570 
notifyAccessibilityButtonAvailabilityChangedInternal(boolean available)1571     private void notifyAccessibilityButtonAvailabilityChangedInternal(boolean available) {
1572         // Only notify the service if it's not been notified or the state has changed
1573         if (mReceivedAccessibilityButtonCallbackSinceBind
1574                 && (mLastAccessibilityButtonCallbackState == available)) {
1575             return;
1576         }
1577         mReceivedAccessibilityButtonCallbackSinceBind = true;
1578         mLastAccessibilityButtonCallbackState = available;
1579         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1580         if (listener != null) {
1581             try {
1582                 if (mTrace.isA11yTracingEnabled()) {
1583                     mTrace.logTrace(
1584                             TRACE_A11Y_SERVICE_CLIENT + ".onAccessibilityButtonAvailabilityChanged",
1585                             String.valueOf(available));
1586                 }
1587                 listener.onAccessibilityButtonAvailabilityChanged(available);
1588             } catch (RemoteException re) {
1589                 Slog.e(LOG_TAG,
1590                         "Error sending accessibility button availability change to " + mService,
1591                         re);
1592             }
1593         }
1594     }
1595 
notifyGestureInternal(AccessibilityGestureEvent gestureInfo)1596     private void notifyGestureInternal(AccessibilityGestureEvent gestureInfo) {
1597         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1598         if (listener != null) {
1599             try {
1600                 if (mTrace.isA11yTracingEnabled()) {
1601                     mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onGesture",
1602                             gestureInfo.toString());
1603                 }
1604                 listener.onGesture(gestureInfo);
1605             } catch (RemoteException re) {
1606                 Slog.e(LOG_TAG, "Error during sending gesture " + gestureInfo
1607                         + " to " + mService, re);
1608             }
1609         }
1610     }
1611 
notifySystemActionsChangedInternal()1612     private void notifySystemActionsChangedInternal() {
1613         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1614         if (listener != null) {
1615             try {
1616                 if (mTrace.isA11yTracingEnabled()) {
1617                     mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".onSystemActionsChanged");
1618                 }
1619                 listener.onSystemActionsChanged();
1620             } catch (RemoteException re) {
1621                 Slog.e(LOG_TAG, "Error sending system actions change to " + mService,
1622                         re);
1623             }
1624         }
1625     }
1626 
notifyClearAccessibilityCacheInternal()1627     private void notifyClearAccessibilityCacheInternal() {
1628         final IAccessibilityServiceClient listener = getServiceInterfaceSafely();
1629         if (listener != null) {
1630             try {
1631                 if (mTrace.isA11yTracingEnabled()) {
1632                     mTrace.logTrace(TRACE_A11Y_SERVICE_CLIENT + ".clearAccessibilityCache");
1633                 }
1634                 listener.clearAccessibilityCache();
1635             } catch (RemoteException re) {
1636                 Slog.e(LOG_TAG, "Error during requesting accessibility info cache"
1637                         + " to be cleared.", re);
1638             }
1639         }
1640     }
1641 
getServiceInterfaceSafely()1642     private IAccessibilityServiceClient getServiceInterfaceSafely() {
1643         synchronized (mLock) {
1644             return mServiceInterface;
1645         }
1646     }
1647 
resolveAccessibilityWindowIdLocked(int accessibilityWindowId)1648     private int resolveAccessibilityWindowIdLocked(int accessibilityWindowId) {
1649         if (accessibilityWindowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) {
1650             return mA11yWindowManager.getActiveWindowId(mSystemSupport.getCurrentUserIdLocked());
1651         }
1652         return accessibilityWindowId;
1653     }
1654 
resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType)1655     private int resolveAccessibilityWindowIdForFindFocusLocked(int windowId, int focusType) {
1656         if (windowId == AccessibilityWindowInfo.ACTIVE_WINDOW_ID) {
1657             return mA11yWindowManager.getActiveWindowId(mSystemSupport.getCurrentUserIdLocked());
1658         }
1659         if (windowId == AccessibilityWindowInfo.ANY_WINDOW_ID) {
1660             return mA11yWindowManager.getFocusedWindowId(focusType);
1661         }
1662         return windowId;
1663     }
1664 
1665     /**
1666      * Request that the system make sure windows are available to interrogate.
1667      *
1668      * @param displayId The logical display id.
1669      */
ensureWindowsAvailableTimedLocked(int displayId)1670     private void ensureWindowsAvailableTimedLocked(int displayId) {
1671         if (mA11yWindowManager.getWindowListLocked(displayId) != null) {
1672             return;
1673         }
1674         // If we have no registered callback, update the state we
1675         // we may have to register one but it didn't happen yet.
1676         if (!mA11yWindowManager.isTrackingWindowsLocked(displayId)) {
1677             // Invokes client change to make sure tracking window enabled.
1678             mSystemSupport.onClientChangeLocked(false);
1679         }
1680         // We have no windows but do not care about them, done.
1681         if (!mA11yWindowManager.isTrackingWindowsLocked(displayId)) {
1682             return;
1683         }
1684 
1685         // Wait for the windows with a timeout.
1686         final long startMillis = SystemClock.uptimeMillis();
1687         while (mA11yWindowManager.getWindowListLocked(displayId) == null) {
1688             final long elapsedMillis = SystemClock.uptimeMillis() - startMillis;
1689             final long remainMillis = WAIT_WINDOWS_TIMEOUT_MILLIS - elapsedMillis;
1690             if (remainMillis <= 0) {
1691                 return;
1692             }
1693             try {
1694                 mLock.wait(remainMillis);
1695             } catch (InterruptedException ie) {
1696                 /* ignore */
1697             }
1698         }
1699     }
1700 
1701     /**
1702      * Perform the specified accessibility action
1703      *
1704      * @param resolvedWindowId The window ID
1705      * [Other parameters match the method on IAccessibilityServiceConnection]
1706      *
1707      * @return Whether or not the action could be sent to the app process
1708      */
performAccessibilityActionInternal(int userId, int resolvedWindowId, long accessibilityNodeId, int action, Bundle arguments, int interactionId, IAccessibilityInteractionConnectionCallback callback, int fetchFlags, long interrogatingTid)1709     private boolean performAccessibilityActionInternal(int userId, int resolvedWindowId,
1710             long accessibilityNodeId, int action, Bundle arguments, int interactionId,
1711             IAccessibilityInteractionConnectionCallback callback, int fetchFlags,
1712             long interrogatingTid) {
1713         RemoteAccessibilityConnection connection;
1714         IBinder activityToken = null;
1715         synchronized (mLock) {
1716             connection = mA11yWindowManager.getConnectionLocked(userId, resolvedWindowId);
1717             if (connection == null)  {
1718                 return false;
1719             }
1720             final boolean isA11yFocusAction = (action == ACTION_ACCESSIBILITY_FOCUS)
1721                     || (action == ACTION_CLEAR_ACCESSIBILITY_FOCUS);
1722             if (!isA11yFocusAction) {
1723                 final WindowInfo windowInfo =
1724                         mA11yWindowManager.findWindowInfoByIdLocked(resolvedWindowId);
1725                 if (windowInfo != null) activityToken = windowInfo.activityToken;
1726             }
1727             final AccessibilityWindowInfo a11yWindowInfo =
1728                     mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId);
1729             if (a11yWindowInfo != null && a11yWindowInfo.isInPictureInPictureMode()
1730                     && mA11yWindowManager.getPictureInPictureActionReplacingConnection() != null
1731                     && !isA11yFocusAction) {
1732                 connection = mA11yWindowManager.getPictureInPictureActionReplacingConnection();
1733             }
1734         }
1735         final int interrogatingPid = Binder.getCallingPid();
1736         final long identityToken = Binder.clearCallingIdentity();
1737         try {
1738             // Regardless of whether or not the action succeeds, it was generated by an
1739             // accessibility service that is driven by user actions, so note user activity.
1740             mPowerManager.userActivity(SystemClock.uptimeMillis(),
1741                     PowerManager.USER_ACTIVITY_EVENT_ACCESSIBILITY, 0);
1742 
1743             if (action == ACTION_CLICK || action == ACTION_LONG_CLICK) {
1744                 mA11yWindowManager.notifyOutsideTouch(userId, resolvedWindowId);
1745             }
1746             if (activityToken != null) {
1747                 LocalServices.getService(ActivityTaskManagerInternal.class)
1748                         .setFocusedActivity(activityToken);
1749             }
1750             connection.getRemote().performAccessibilityAction(accessibilityNodeId, action,
1751                     arguments, interactionId, callback, fetchFlags, interrogatingPid,
1752                     interrogatingTid);
1753         } catch (RemoteException re) {
1754             if (DEBUG) {
1755                 Slog.e(LOG_TAG, "Error calling performAccessibilityAction: " + re);
1756             }
1757             return false;
1758         } finally {
1759             Binder.restoreCallingIdentity(identityToken);
1760         }
1761         return true;
1762     }
1763 
1764     /**
1765      * Replace the interaction callback if needed, for example if the window is in picture-
1766      * in-picture mode and needs its nodes replaced.
1767      *
1768      * @param originalCallback The callback we were planning to use
1769      * @param resolvedWindowId The ID of the window we're calling
1770      * @param interactionId The id for the original callback
1771      * @param interrogatingPid Process ID of requester
1772      * @param interrogatingTid Thread ID of requester
1773      *
1774      * @return The callback to use, which may be the original one.
1775      */
replaceCallbackIfNeeded( IAccessibilityInteractionConnectionCallback originalCallback, int resolvedWindowId, int interactionId, int interrogatingPid, long interrogatingTid)1776     private IAccessibilityInteractionConnectionCallback replaceCallbackIfNeeded(
1777             IAccessibilityInteractionConnectionCallback originalCallback, int resolvedWindowId,
1778             int interactionId, int interrogatingPid, long interrogatingTid) {
1779         final RemoteAccessibilityConnection pipActionReplacingConnection =
1780                 mA11yWindowManager.getPictureInPictureActionReplacingConnection();
1781         synchronized (mLock) {
1782             final AccessibilityWindowInfo windowInfo =
1783                     mA11yWindowManager.findA11yWindowInfoByIdLocked(resolvedWindowId);
1784             if ((windowInfo == null) || !windowInfo.isInPictureInPictureMode()
1785                 || (pipActionReplacingConnection == null)) {
1786                 return originalCallback;
1787             }
1788         }
1789         return new ActionReplacingCallback(originalCallback,
1790                 pipActionReplacingConnection.getRemote(), interactionId,
1791                 interrogatingPid, interrogatingTid);
1792     }
1793 
getWindowsByDisplayLocked(int displayId)1794     private List<AccessibilityWindowInfo> getWindowsByDisplayLocked(int displayId) {
1795         final List<AccessibilityWindowInfo> internalWindowList =
1796                 mA11yWindowManager.getWindowListLocked(displayId);
1797         if (internalWindowList == null) {
1798             return null;
1799         }
1800         final List<AccessibilityWindowInfo> returnedWindowList = new ArrayList<>();
1801         final int windowCount = internalWindowList.size();
1802         for (int i = 0; i < windowCount; i++) {
1803             AccessibilityWindowInfo window = internalWindowList.get(i);
1804             AccessibilityWindowInfo windowClone =
1805                     AccessibilityWindowInfo.obtain(window);
1806             windowClone.setConnectionId(mId);
1807             returnedWindowList.add(windowClone);
1808         }
1809         return returnedWindowList;
1810     }
1811 
getComponentName()1812     public ComponentName getComponentName() {
1813         return mComponentName;
1814     }
1815 
1816     private final class InvocationHandler extends Handler {
1817         public static final int MSG_ON_GESTURE = 1;
1818         public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2;
1819 
1820         private static final int MSG_ON_MAGNIFICATION_CHANGED = 5;
1821         private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6;
1822         private static final int MSG_ON_ACCESSIBILITY_BUTTON_CLICKED = 7;
1823         private static final int MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED = 8;
1824         private static final int MSG_ON_SYSTEM_ACTIONS_CHANGED = 9;
1825 
1826         /** List of magnification callback states, mapping from displayId -> Boolean */
1827         @GuardedBy("mlock")
1828         private final SparseArray<Boolean> mMagnificationCallbackState = new SparseArray<>(0);
1829         private boolean mIsSoftKeyboardCallbackEnabled = false;
1830 
InvocationHandler(Looper looper)1831         public InvocationHandler(Looper looper) {
1832             super(looper, null, true);
1833         }
1834 
1835         @Override
handleMessage(Message message)1836         public void handleMessage(Message message) {
1837             final int type = message.what;
1838             switch (type) {
1839                 case MSG_ON_GESTURE: {
1840                     notifyGestureInternal((AccessibilityGestureEvent) message.obj);
1841                 } break;
1842 
1843                 case MSG_CLEAR_ACCESSIBILITY_CACHE: {
1844                     notifyClearAccessibilityCacheInternal();
1845                 } break;
1846 
1847                 case MSG_ON_MAGNIFICATION_CHANGED: {
1848                     final SomeArgs args = (SomeArgs) message.obj;
1849                     final Region region = (Region) args.arg1;
1850                     final float scale = (float) args.arg2;
1851                     final float centerX = (float) args.arg3;
1852                     final float centerY = (float) args.arg4;
1853                     final int displayId = args.argi1;
1854                     notifyMagnificationChangedInternal(displayId, region, scale, centerX, centerY);
1855                     args.recycle();
1856                 } break;
1857 
1858                 case MSG_ON_SOFT_KEYBOARD_STATE_CHANGED: {
1859                     final int showState = (int) message.arg1;
1860                     notifySoftKeyboardShowModeChangedInternal(showState);
1861                 } break;
1862 
1863                 case MSG_ON_ACCESSIBILITY_BUTTON_CLICKED: {
1864                     final int displayId = (int) message.arg1;
1865                     notifyAccessibilityButtonClickedInternal(displayId);
1866                 } break;
1867 
1868                 case MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED: {
1869                     final boolean available = (message.arg1 != 0);
1870                     notifyAccessibilityButtonAvailabilityChangedInternal(available);
1871                 } break;
1872                 case MSG_ON_SYSTEM_ACTIONS_CHANGED: {
1873                     notifySystemActionsChangedInternal();
1874                     break;
1875                 }
1876                 default: {
1877                     throw new IllegalArgumentException("Unknown message: " + type);
1878                 }
1879             }
1880         }
1881 
notifyMagnificationChangedLocked(int displayId, @NonNull Region region, float scale, float centerX, float centerY)1882         public void notifyMagnificationChangedLocked(int displayId, @NonNull Region region,
1883                 float scale, float centerX, float centerY) {
1884             synchronized (mLock) {
1885                 if (mMagnificationCallbackState.get(displayId) == null) {
1886                     return;
1887                 }
1888             }
1889 
1890             final SomeArgs args = SomeArgs.obtain();
1891             args.arg1 = region;
1892             args.arg2 = scale;
1893             args.arg3 = centerX;
1894             args.arg4 = centerY;
1895             args.argi1 = displayId;
1896 
1897             final Message msg = obtainMessage(MSG_ON_MAGNIFICATION_CHANGED, args);
1898             msg.sendToTarget();
1899         }
1900 
setMagnificationCallbackEnabled(int displayId, boolean enabled)1901         public void setMagnificationCallbackEnabled(int displayId, boolean enabled) {
1902             synchronized (mLock) {
1903                 if (enabled) {
1904                     mMagnificationCallbackState.put(displayId, true);
1905                 } else {
1906                     mMagnificationCallbackState.remove(displayId);
1907                 }
1908             }
1909         }
1910 
isMagnificationCallbackEnabled(int displayId)1911         public boolean isMagnificationCallbackEnabled(int displayId) {
1912             synchronized (mLock) {
1913                 return mMagnificationCallbackState.get(displayId) != null;
1914             }
1915         }
1916 
notifySoftKeyboardShowModeChangedLocked(int showState)1917         public void notifySoftKeyboardShowModeChangedLocked(int showState) {
1918             if (!mIsSoftKeyboardCallbackEnabled) {
1919                 return;
1920             }
1921 
1922             final Message msg = obtainMessage(MSG_ON_SOFT_KEYBOARD_STATE_CHANGED, showState, 0);
1923             msg.sendToTarget();
1924         }
1925 
setSoftKeyboardCallbackEnabled(boolean enabled)1926         public void setSoftKeyboardCallbackEnabled(boolean enabled) {
1927             mIsSoftKeyboardCallbackEnabled = enabled;
1928         }
1929 
notifyAccessibilityButtonClickedLocked(int displayId)1930         public void notifyAccessibilityButtonClickedLocked(int displayId) {
1931             final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_CLICKED, displayId, 0);
1932             msg.sendToTarget();
1933         }
1934 
notifyAccessibilityButtonAvailabilityChangedLocked(boolean available)1935         public void notifyAccessibilityButtonAvailabilityChangedLocked(boolean available) {
1936             final Message msg = obtainMessage(MSG_ON_ACCESSIBILITY_BUTTON_AVAILABILITY_CHANGED,
1937                     (available ? 1 : 0), 0);
1938             msg.sendToTarget();
1939         }
1940     }
1941 
isServiceHandlesDoubleTapEnabled()1942     public boolean isServiceHandlesDoubleTapEnabled() {
1943         return mServiceHandlesDoubleTap;
1944     }
1945 
isMultiFingerGesturesEnabled()1946     public boolean isMultiFingerGesturesEnabled() {
1947         return mRequestMultiFingerGestures;
1948     }
1949 
isTwoFingerPassthroughEnabled()1950     public boolean isTwoFingerPassthroughEnabled() {
1951         return mRequestTwoFingerPassthrough;
1952     }
1953 
isSendMotionEventsEnabled()1954     public boolean isSendMotionEventsEnabled() {
1955         return mSendMotionEvents;
1956     }
1957 
1958     @Override
setGestureDetectionPassthroughRegion(int displayId, Region region)1959     public void setGestureDetectionPassthroughRegion(int displayId, Region region) {
1960         if (mTrace.isA11yTracingEnabled()) {
1961             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setGestureDetectionPassthroughRegion",
1962                     "displayId=" + displayId + ";region=" + region);
1963         }
1964         mSystemSupport.setGestureDetectionPassthroughRegion(displayId, region);
1965     }
1966 
1967     @Override
setTouchExplorationPassthroughRegion(int displayId, Region region)1968     public void setTouchExplorationPassthroughRegion(int displayId, Region region) {
1969         if (mTrace.isA11yTracingEnabled()) {
1970             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setTouchExplorationPassthroughRegion",
1971                     "displayId=" + displayId + ";region=" + region);
1972         }
1973         mSystemSupport.setTouchExplorationPassthroughRegion(displayId, region);
1974     }
1975 
1976     @Override
setFocusAppearance(int strokeWidth, int color)1977     public void setFocusAppearance(int strokeWidth, int color) {
1978         if (mTrace.isA11yTracingEnabled()) {
1979             mTrace.logTrace(TRACE_A11Y_SERVICE_CONNECTION + ".setFocusAppearance",
1980                     "strokeWidth=" + strokeWidth + ";color=" + color);
1981         }
1982     }
1983 
1984     @Override
logTrace(long timestamp, String where, String callingParams, int processId, long threadId, int callingUid, Bundle callingStack)1985     public void logTrace(long timestamp, String where, String callingParams, int processId,
1986             long threadId, int callingUid, Bundle callingStack) {
1987         if (mTrace.isA11yTracingEnabled()) {
1988             ArrayList<StackTraceElement> list =
1989                     (ArrayList<StackTraceElement>) callingStack.getSerializable(CALL_STACK);
1990             mTrace.logTrace(timestamp, where, callingParams, processId, threadId, callingUid,
1991                     list.toArray(new StackTraceElement[list.size()]));
1992         }
1993     }
1994 }
1995