• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 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 android.accessibilityservice.cts;
18 
19 import static com.google.common.truth.Truth.assertThat;
20 import static com.google.common.truth.Truth.assertWithMessage;
21 
22 import static org.junit.Assert.assertEquals;
23 import static org.junit.Assert.assertSame;
24 import static org.junit.Assert.assertThrows;
25 
26 import android.accessibility.cts.common.AccessibilityDumpOnFailureRule;
27 import android.accessibility.cts.common.InstrumentedAccessibilityService;
28 import android.accessibilityservice.AccessibilityService;
29 import android.accessibilityservice.AccessibilityServiceInfo;
30 import android.os.Parcel;
31 import android.platform.test.annotations.AsbSecurityTest;
32 import android.platform.test.annotations.Presubmit;
33 import android.platform.test.flag.junit.CheckFlagsRule;
34 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
35 import android.view.accessibility.AccessibilityEvent;
36 
37 import androidx.test.ext.junit.runners.AndroidJUnit4;
38 import androidx.test.filters.MediumTest;
39 
40 import com.android.compatibility.common.util.CddTest;
41 import com.android.sts.common.util.StsExtraBusinessLogicTestCase;
42 
43 import org.junit.Rule;
44 import org.junit.Test;
45 import org.junit.runner.RunWith;
46 
47 import java.lang.reflect.Field;
48 import java.lang.reflect.InvocationTargetException;
49 import java.lang.reflect.Method;
50 
51 /**
52  * Class for testing {@link AccessibilityServiceInfo}.
53  */
54 @Presubmit
55 @RunWith(AndroidJUnit4.class)
56 @CddTest(requirements = {"3.10/C-1-1,C-1-2"})
57 public class AccessibilityServiceInfoTest extends StsExtraBusinessLogicTestCase {
58 
59     @Rule
60     public final AccessibilityDumpOnFailureRule mDumpOnFailureRule =
61             new AccessibilityDumpOnFailureRule();
62 
63     @Rule
64     public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
65 
66     @MediumTest
67     @Test
testMarshalling()68     public void testMarshalling() throws Exception {
69 
70         // fully populate the service info to marshal
71         AccessibilityServiceInfo sentInfo = new AccessibilityServiceInfo();
72         fullyPopulateSentAccessibilityServiceInfo(sentInfo);
73 
74         // marshal and unmarshal the service info
75         Parcel parcel = Parcel.obtain();
76         sentInfo.writeToParcel(parcel, 0);
77         parcel.setDataPosition(0);
78         AccessibilityServiceInfo receivedInfo = AccessibilityServiceInfo.CREATOR
79                 .createFromParcel(parcel);
80 
81         // make sure all fields properly marshaled
82         assertAllFieldsProperlyMarshalled(sentInfo, receivedInfo);
83     }
84 
85     /**
86      * Tests whether the service info describes its contents consistently.
87      */
88     @MediumTest
89     @Test
testDescribeContents()90     public void testDescribeContents() {
91         AccessibilityServiceInfo info = new AccessibilityServiceInfo();
92         assertSame("Accessibility service info always return 0 for this method.", 0,
93                 info.describeContents());
94         fullyPopulateSentAccessibilityServiceInfo(info);
95         assertSame("Accessibility service infos always return 0 for this method.", 0,
96                 info.describeContents());
97     }
98 
99     /**
100      * Tests whether a feedback type is correctly transformed to a string.
101      */
102     @MediumTest
103     @Test
testFeedbackTypeToString()104     public void testFeedbackTypeToString() {
105         assertEquals("[FEEDBACK_AUDIBLE]", AccessibilityServiceInfo.feedbackTypeToString(
106                 AccessibilityServiceInfo.FEEDBACK_AUDIBLE));
107         assertEquals("[FEEDBACK_GENERIC]", AccessibilityServiceInfo.feedbackTypeToString(
108                 AccessibilityServiceInfo.FEEDBACK_GENERIC));
109         assertEquals("[FEEDBACK_HAPTIC]", AccessibilityServiceInfo.feedbackTypeToString(
110                 AccessibilityServiceInfo.FEEDBACK_HAPTIC));
111         assertEquals("[FEEDBACK_SPOKEN]", AccessibilityServiceInfo.feedbackTypeToString(
112                 AccessibilityServiceInfo.FEEDBACK_SPOKEN));
113         assertEquals("[FEEDBACK_VISUAL]", AccessibilityServiceInfo.feedbackTypeToString(
114                 AccessibilityServiceInfo.FEEDBACK_VISUAL));
115         assertEquals("[FEEDBACK_BRAILLE]", AccessibilityServiceInfo.feedbackTypeToString(
116                 AccessibilityServiceInfo.FEEDBACK_BRAILLE));
117         assertEquals("[FEEDBACK_SPOKEN, FEEDBACK_HAPTIC, FEEDBACK_AUDIBLE, FEEDBACK_VISUAL,"
118                 + " FEEDBACK_GENERIC, FEEDBACK_BRAILLE]",
119                 AccessibilityServiceInfo.feedbackTypeToString(
120                         AccessibilityServiceInfo.FEEDBACK_ALL_MASK));
121     }
122 
123     /**
124      * Tests whether a flag is correctly transformed to a string.
125      */
126     @MediumTest
127     @Test
testFlagToString()128     public void testFlagToString() {
129         assertEquals("DEFAULT", AccessibilityServiceInfo.flagToString(
130                 AccessibilityServiceInfo.DEFAULT));
131         assertEquals("FLAG_INCLUDE_NOT_IMPORTANT_VIEWS", AccessibilityServiceInfo.flagToString(
132                 AccessibilityServiceInfo.FLAG_INCLUDE_NOT_IMPORTANT_VIEWS));
133         assertEquals("FLAG_REPORT_VIEW_IDS", AccessibilityServiceInfo.flagToString(
134                 AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS));
135         assertEquals("FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY", AccessibilityServiceInfo
136                 .flagToString(AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY));
137         assertEquals("FLAG_REQUEST_FILTER_KEY_EVENTS", AccessibilityServiceInfo.flagToString(
138                 AccessibilityServiceInfo.FLAG_REQUEST_FILTER_KEY_EVENTS));
139         assertEquals("FLAG_REQUEST_TOUCH_EXPLORATION_MODE", AccessibilityServiceInfo.flagToString(
140                 AccessibilityServiceInfo.FLAG_REQUEST_TOUCH_EXPLORATION_MODE));
141         assertEquals("FLAG_RETRIEVE_INTERACTIVE_WINDOWS", AccessibilityServiceInfo.flagToString(
142                 AccessibilityServiceInfo.FLAG_RETRIEVE_INTERACTIVE_WINDOWS));
143         assertEquals("FLAG_ENABLE_ACCESSIBILITY_VOLUME", AccessibilityServiceInfo.flagToString(
144                 AccessibilityServiceInfo.FLAG_ENABLE_ACCESSIBILITY_VOLUME));
145         assertEquals("FLAG_REQUEST_ACCESSIBILITY_BUTTON", AccessibilityServiceInfo.flagToString(
146                 AccessibilityServiceInfo.FLAG_REQUEST_ACCESSIBILITY_BUTTON));
147         assertEquals("FLAG_REQUEST_FINGERPRINT_GESTURES", AccessibilityServiceInfo.flagToString(
148                 AccessibilityServiceInfo.FLAG_REQUEST_FINGERPRINT_GESTURES));
149         assertEquals(
150                 "FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK",
151                 AccessibilityServiceInfo.flagToString(
152                         AccessibilityServiceInfo
153                                 .FLAG_REQUEST_SHORTCUT_WARNING_DIALOG_SPOKEN_FEEDBACK));
154     }
155 
156     @Test
157     @AsbSecurityTest(cveBugId = {277072324})
testSetServiceInfo_throwsForLargeServiceInfo_calledUsingReflection()158     public void testSetServiceInfo_throwsForLargeServiceInfo_calledUsingReflection()
159             throws Exception {
160         try {
161             final InstrumentedAccessibilityService service =
162                     InstrumentedAccessibilityService.enableService(
163                             InstrumentedAccessibilityService.class);
164             final AccessibilityServiceInfo info = service.getServiceInfo();
165             setLargePackageNames(info);
166 
167             // NOTE: Using reflection requires setting the HIDDEN_API_POLICY global setting.
168             // This is done in AndroidTest.xml for this test because it must be set before
169             // the test process is started.
170             final Field connectionIdField = AccessibilityService.class.getDeclaredField(
171                     "mConnectionId");
172             connectionIdField.setAccessible(true); // Allow the test to read this private field.
173             final Method getConnection =
174                     Class.forName("android.view.accessibility.AccessibilityInteractionClient")
175                             .getDeclaredMethod("getConnection", int.class);
176             final Object connection = getConnection.invoke(null, connectionIdField.get(service));
177             final Method setServiceInfo =
178                     Class.forName("android.accessibilityservice.IAccessibilityServiceConnection")
179                             .getDeclaredMethod("setServiceInfo", AccessibilityServiceInfo.class);
180 
181             InvocationTargetException exception = assertThrows(
182                     InvocationTargetException.class, () -> setServiceInfo.invoke(connection, info));
183             assertThat(exception).hasCauseThat().isInstanceOf(IllegalStateException.class);
184         } finally {
185             InstrumentedAccessibilityService.disableAllServices();
186         }
187     }
188 
189     @Test
190     @AsbSecurityTest(cveBugId = {261589597})
testSetServiceInfo_throwsForLargeServiceInfo()191     public void testSetServiceInfo_throwsForLargeServiceInfo() {
192         try {
193             final InstrumentedAccessibilityService service =
194                     InstrumentedAccessibilityService.enableService(
195                             InstrumentedAccessibilityService.class);
196             final AccessibilityServiceInfo info = service.getServiceInfo();
197             setLargePackageNames(info);
198 
199             assertThrows(IllegalStateException.class, () -> service.setServiceInfo(info));
200         } finally {
201             InstrumentedAccessibilityService.disableAllServices();
202         }
203     }
204 
205     @Test
testDefaultConstructor()206     public void testDefaultConstructor() throws Exception {
207         AccessibilityServiceInfo info = new AccessibilityServiceInfo();
208 
209         assertWithMessage("info.getId()").that(info.getId()).isNull();
210         assertWithMessage("info.toString()").that(info.toString()).isNotNull();
211     }
212 
213     @Test
testDynamicallyConfigurableProperties_doNotPersist()214     public void testDynamicallyConfigurableProperties_doNotPersist() {
215         try {
216             final int flag = AccessibilityServiceInfo.FLAG_REPORT_VIEW_IDS;
217             final InstrumentedAccessibilityService service =
218                     InstrumentedAccessibilityService.enableService(
219                             InstrumentedAccessibilityService.class);
220             final AccessibilityServiceInfo info = service.getServiceInfo();
221             assertThat(info.flags & flag).isEqualTo(0);
222             info.flags |= flag;
223             service.setServiceInfo(info);
224             assertThat(service.getServiceInfo().flags & flag).isEqualTo(flag);
225             InstrumentedAccessibilityService.disableAllServices();
226 
227             final InstrumentedAccessibilityService reenabledService =
228                     InstrumentedAccessibilityService.enableService(
229                             InstrumentedAccessibilityService.class);
230             assertThat(reenabledService.getServiceInfo().flags & flag).isEqualTo(0);
231         } finally {
232             InstrumentedAccessibilityService.disableAllServices();
233         }
234     }
235 
236     /**
237      * Fully populates the {@link AccessibilityServiceInfo} to marshal.
238      *
239      * @param sentInfo The service info to populate.
240      */
fullyPopulateSentAccessibilityServiceInfo(AccessibilityServiceInfo sentInfo)241     private void fullyPopulateSentAccessibilityServiceInfo(AccessibilityServiceInfo sentInfo) {
242         sentInfo.eventTypes = AccessibilityEvent.TYPE_VIEW_CLICKED;
243         sentInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_SPOKEN;
244         sentInfo.flags = AccessibilityServiceInfo.DEFAULT;
245         sentInfo.notificationTimeout = 1000;
246         sentInfo.packageNames = new String[] {
247             "foo.bar.baz"
248         };
249         sentInfo.setInteractiveUiTimeoutMillis(2000);
250         sentInfo.setNonInteractiveUiTimeoutMillis(4000);
251         sentInfo.setAccessibilityTool(true);
252     }
253 
254     /**
255      * Compares all properties of the <code>sentInfo</code> and the
256      * <code>receviedInfo</code> to make sure marshaling is correctly
257      * implemented.
258      */
assertAllFieldsProperlyMarshalled(AccessibilityServiceInfo sentInfo, AccessibilityServiceInfo receivedInfo)259     private void assertAllFieldsProperlyMarshalled(AccessibilityServiceInfo sentInfo,
260             AccessibilityServiceInfo receivedInfo) {
261         assertEquals("eventTypes not marshalled properly", sentInfo.eventTypes,
262                 receivedInfo.eventTypes);
263         assertEquals("feedbackType not marshalled properly", sentInfo.feedbackType,
264                 receivedInfo.feedbackType);
265         assertEquals("flags not marshalled properly", sentInfo.flags, receivedInfo.flags);
266         assertEquals("notificationTimeout not marshalled properly", sentInfo.notificationTimeout,
267                 receivedInfo.notificationTimeout);
268         assertEquals("packageNames not marshalled properly", sentInfo.packageNames.length,
269                 receivedInfo.packageNames.length);
270         assertEquals("packageNames not marshalled properly", sentInfo.packageNames[0],
271                 receivedInfo.packageNames[0]);
272         assertEquals("interactiveUiTimeout not marshalled properly",
273                 sentInfo.getInteractiveUiTimeoutMillis(),
274                 receivedInfo.getInteractiveUiTimeoutMillis());
275         assertEquals("nonInteractiveUiTimeout not marshalled properly",
276                 sentInfo.getNonInteractiveUiTimeoutMillis(),
277                 receivedInfo.getNonInteractiveUiTimeoutMillis());
278         assertEquals("isAccessibilityTool not marshalled properly",
279                 sentInfo.isAccessibilityTool(), receivedInfo.isAccessibilityTool());
280     }
281 
setLargePackageNames(AccessibilityServiceInfo info)282     private static void setLargePackageNames(AccessibilityServiceInfo info) {
283         // android_util_Binder.cpp says that very large transactions (above 200*1024 bytes)
284         // will fail with TransactionTooLargeException, but the accessibility framework uses the
285         // more aggressive suggested individual parcel size limit of IBinder.java's
286         // MAX_IPC_SIZE (64*1024 bytes).
287         info.packageNames = new String[]{"A".repeat(1024 * 32)};
288     }
289 }
290