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 junit.framework.Assert.assertFalse;
20 import static junit.framework.Assert.assertTrue;
21 
22 import static org.mockito.ArgumentMatchers.any;
23 import static org.mockito.ArgumentMatchers.anyInt;
24 import static org.mockito.ArgumentMatchers.eq;
25 import static org.mockito.Mockito.mock;
26 import static org.mockito.Mockito.never;
27 import static org.mockito.Mockito.times;
28 import static org.mockito.Mockito.verify;
29 import static org.mockito.Mockito.when;
30 
31 import android.accessibilityservice.AccessibilityServiceInfo;
32 import android.accessibilityservice.AccessibilityTrace;
33 import android.accessibilityservice.GestureDescription;
34 import android.accessibilityservice.IAccessibilityServiceClient;
35 import android.content.ComponentName;
36 import android.content.Context;
37 import android.content.Intent;
38 import android.content.pm.ApplicationInfo;
39 import android.content.pm.ParceledListSlice;
40 import android.content.pm.ResolveInfo;
41 import android.content.pm.ServiceInfo;
42 import android.os.IBinder;
43 import android.os.RemoteException;
44 import android.os.UserHandle;
45 import android.testing.DexmakerShareClassLoaderRule;
46 import android.view.Display;
47 
48 import com.android.server.accessibility.magnification.MagnificationProcessor;
49 import com.android.server.accessibility.test.MessageCapturingHandler;
50 import com.android.server.wm.ActivityTaskManagerInternal;
51 import com.android.server.wm.WindowManagerInternal;
52 
53 import org.junit.After;
54 import org.junit.Before;
55 import org.junit.Rule;
56 import org.junit.Test;
57 import org.mockito.Mock;
58 import org.mockito.MockitoAnnotations;
59 
60 import java.util.Arrays;
61 import java.util.Collections;
62 import java.util.HashSet;
63 import java.util.List;
64 
65 
66 /**
67  * Tests for AccessibilityServiceConnection
68  */
69 public class AccessibilityServiceConnectionTest {
70     static final ComponentName COMPONENT_NAME = new ComponentName(
71             "com.android.server.accessibility", "AccessibilityServiceConnectionTest");
72     static final int SERVICE_ID = 42;
73 
74     // Mock package-private AccessibilityUserState class
75     @Rule
76     public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
77             new DexmakerShareClassLoaderRule();
78 
79     AccessibilityServiceConnection mConnection;
80 
81     @Mock AccessibilityUserState mMockUserState;
82     @Mock Context mMockContext;
83     @Mock AccessibilityServiceInfo mMockServiceInfo;
84     @Mock ResolveInfo mMockResolveInfo;
85     @Mock AccessibilitySecurityPolicy mMockSecurityPolicy;
86     @Mock AccessibilityWindowManager mMockA11yWindowManager;
87     @Mock ActivityTaskManagerInternal mMockActivityTaskManagerInternal;
88     @Mock AbstractAccessibilityServiceConnection.SystemSupport mMockSystemSupport;
89     @Mock AccessibilityTrace mMockA11yTrace;
90     @Mock WindowManagerInternal mMockWindowManagerInternal;
91     @Mock SystemActionPerformer mMockSystemActionPerformer;
92     @Mock KeyEventDispatcher mMockKeyEventDispatcher;
93     @Mock
94     MagnificationProcessor mMockMagnificationProcessor;
95     @Mock IBinder mMockIBinder;
96     @Mock IAccessibilityServiceClient mMockServiceClient;
97     @Mock MotionEventInjector mMockMotionEventInjector;
98 
99     MessageCapturingHandler mHandler = new MessageCapturingHandler(null);
100 
101     @Before
setup()102     public void setup() {
103         MockitoAnnotations.initMocks(this);
104         when(mMockSystemSupport.getKeyEventDispatcher()).thenReturn(mMockKeyEventDispatcher);
105         when(mMockSystemSupport.getMagnificationProcessor())
106                 .thenReturn(mMockMagnificationProcessor);
107         when(mMockSystemSupport.getMotionEventInjectorForDisplayLocked(
108                 Display.DEFAULT_DISPLAY)).thenReturn(mMockMotionEventInjector);
109 
110         when(mMockServiceInfo.getResolveInfo()).thenReturn(mMockResolveInfo);
111         mMockResolveInfo.serviceInfo = mock(ServiceInfo.class);
112         mMockResolveInfo.serviceInfo.applicationInfo = mock(ApplicationInfo.class);
113 
114         when(mMockIBinder.queryLocalInterface(any())).thenReturn(mMockServiceClient);
115         when(mMockA11yTrace.isA11yTracingEnabled()).thenReturn(false);
116 
117         mConnection = new AccessibilityServiceConnection(mMockUserState, mMockContext,
118                 COMPONENT_NAME, mMockServiceInfo, SERVICE_ID, mHandler, new Object(),
119                 mMockSecurityPolicy, mMockSystemSupport, mMockA11yTrace,
120                 mMockWindowManagerInternal, mMockSystemActionPerformer,
121                 mMockA11yWindowManager, mMockActivityTaskManagerInternal);
122         when(mMockSecurityPolicy.canPerformGestures(mConnection)).thenReturn(true);
123     }
124 
125     @After
tearDown()126     public void tearDown() {
127         mHandler.removeAllMessages();
128     }
129 
130 
131     @Test
bind_requestsContextToBindService()132     public void bind_requestsContextToBindService() {
133         mConnection.bindLocked();
134         verify(mMockContext).bindServiceAsUser(any(Intent.class), eq(mConnection),
135                 eq(Context.BIND_AUTO_CREATE
136                         | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE
137                         | Context.BIND_ALLOW_BACKGROUND_ACTIVITY_STARTS
138                         | Context.BIND_INCLUDE_CAPABILITIES),
139                 any(UserHandle.class));
140     }
141 
142     @Test
unbind_requestsContextToUnbindService()143     public void unbind_requestsContextToUnbindService() {
144         mConnection.unbindLocked();
145         verify(mMockContext).unbindService(mConnection);
146     }
147 
148     @Test
bindConnectUnbind_linksAndUnlinksToServiceDeath()149     public void bindConnectUnbind_linksAndUnlinksToServiceDeath() throws RemoteException {
150         setServiceBinding(COMPONENT_NAME);
151         mConnection.bindLocked();
152         mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
153         verify(mMockIBinder).linkToDeath(eq(mConnection), anyInt());
154         mConnection.unbindLocked();
155         verify(mMockIBinder).unlinkToDeath(eq(mConnection), anyInt());
156     }
157 
158     @Test
connectedServiceCrashedAndRestarted_crashReportedInServiceInfo()159     public void connectedServiceCrashedAndRestarted_crashReportedInServiceInfo() {
160         setServiceBinding(COMPONENT_NAME);
161         mConnection.bindLocked();
162         mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
163         assertFalse(mConnection.getServiceInfo().crashed);
164         mConnection.binderDied();
165         assertTrue(mConnection.getServiceInfo().crashed);
166         mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
167         mHandler.sendAllMessages();
168         assertFalse(mConnection.getServiceInfo().crashed);
169     }
170 
setServiceBinding(ComponentName componentName)171     private void setServiceBinding(ComponentName componentName) {
172         when(mMockUserState.getBindingServicesLocked())
173                 .thenReturn(new HashSet<>(Arrays.asList(componentName)));
174     }
175 
176     @Test
binderDied_keysGetFlushed()177     public void binderDied_keysGetFlushed() {
178         setServiceBinding(COMPONENT_NAME);
179         mConnection.bindLocked();
180         mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
181         mConnection.binderDied();
182         assertTrue(mConnection.getServiceInfo().crashed);
183         verify(mMockKeyEventDispatcher).flush(mConnection);
184     }
185 
186     @Test
connectedService_notInEnabledServiceList_doNotInitClient()187     public void connectedService_notInEnabledServiceList_doNotInitClient()
188             throws RemoteException {
189         when(mMockUserState.getEnabledServicesLocked())
190                 .thenReturn(Collections.emptySet());
191         setServiceBinding(COMPONENT_NAME);
192 
193         mConnection.bindLocked();
194         mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
195         mHandler.sendAllMessages();
196         verify(mMockSystemSupport, times(2)).onClientChangeLocked(false);
197         verify(mMockServiceClient, times(0)).init(any(), anyInt(), any());
198     }
199 
200     @Test
sendGesture_touchableDevice_injectEvents()201     public void sendGesture_touchableDevice_injectEvents()
202             throws RemoteException {
203         when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(true);
204         setServiceBinding(COMPONENT_NAME);
205         mConnection.bindLocked();
206         mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
207 
208         ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
209         List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
210         when(parceledListSlice.getList()).thenReturn(gestureSteps);
211         mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
212 
213         verify(mMockMotionEventInjector).injectEvents(gestureSteps, mMockServiceClient, 0,
214                 Display.DEFAULT_DISPLAY);
215     }
216 
217     @Test
sendGesture_untouchableDevice_performGestureResultFailed()218     public void sendGesture_untouchableDevice_performGestureResultFailed()
219             throws RemoteException {
220         when(mMockWindowManagerInternal.isTouchOrFaketouchDevice()).thenReturn(false);
221         setServiceBinding(COMPONENT_NAME);
222         mConnection.bindLocked();
223         mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
224 
225         ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
226         List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
227         when(parceledListSlice.getList()).thenReturn(gestureSteps);
228         mConnection.dispatchGesture(0, parceledListSlice, Display.DEFAULT_DISPLAY);
229 
230         verify(mMockMotionEventInjector, never()).injectEvents(gestureSteps, mMockServiceClient, 0,
231                 Display.DEFAULT_DISPLAY);
232         verify(mMockServiceClient).onPerformGestureResult(0, false);
233     }
234 
235     @Test
sendGesture_invalidDisplay_performGestureResultFailed()236     public void sendGesture_invalidDisplay_performGestureResultFailed()
237             throws RemoteException {
238         setServiceBinding(COMPONENT_NAME);
239         mConnection.bindLocked();
240         mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
241 
242         ParceledListSlice parceledListSlice = mock(ParceledListSlice.class);
243         List<GestureDescription.GestureStep> gestureSteps = mock(List.class);
244         when(parceledListSlice.getList()).thenReturn(gestureSteps);
245         mConnection.dispatchGesture(0, parceledListSlice, Display.INVALID_DISPLAY);
246 
247         verify(mMockServiceClient).onPerformGestureResult(0, false);
248     }
249 
250     @Test
unbind_resetAllMagnification()251     public void unbind_resetAllMagnification() {
252         mConnection.unbindLocked();
253         verify(mMockMagnificationProcessor).resetAllIfNeeded(anyInt());
254     }
255 
256     @Test
binderDied_resetAllMagnification()257     public void binderDied_resetAllMagnification() {
258         setServiceBinding(COMPONENT_NAME);
259         mConnection.bindLocked();
260         mConnection.onServiceConnected(COMPONENT_NAME, mMockIBinder);
261 
262         mConnection.binderDied();
263 
264         verify(mMockMagnificationProcessor).resetAllIfNeeded(anyInt());
265     }
266 
267 }
268