1 /*
2  * Copyright (C) 2019 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.content.pm.PackageManagerInternal.PACKAGE_INSTALLER;
20 
21 import android.Manifest;
22 import android.accessibilityservice.AccessibilityServiceInfo;
23 import android.annotation.NonNull;
24 import android.annotation.Nullable;
25 import android.app.AppOpsManager;
26 import android.appwidget.AppWidgetManagerInternal;
27 import android.content.ComponentName;
28 import android.content.Context;
29 import android.content.pm.InstallSourceInfo;
30 import android.content.pm.PackageManager;
31 import android.content.pm.PackageManagerInternal;
32 import android.content.pm.ResolveInfo;
33 import android.content.pm.ServiceInfo;
34 import android.content.pm.UserInfo;
35 import android.os.Binder;
36 import android.os.IBinder;
37 import android.os.Process;
38 import android.os.UserHandle;
39 import android.os.UserManager;
40 import android.text.TextUtils;
41 import android.util.ArraySet;
42 import android.util.Slog;
43 import android.view.accessibility.AccessibilityEvent;
44 
45 import com.android.internal.util.ArrayUtils;
46 import com.android.server.LocalServices;
47 
48 import libcore.util.EmptyArray;
49 
50 import java.util.ArrayList;
51 import java.util.Set;
52 
53 /**
54  * This class provides APIs of accessibility security policies for accessibility manager
55  * to grant accessibility capabilities or events access right to accessibility services. And also
56  * monitors the current bound accessibility services to prompt permission warnings for
57  * not accessibility-categorized ones.
58  */
59 public class AccessibilitySecurityPolicy {
60     private static final int OWN_PROCESS_ID = android.os.Process.myPid();
61     private static final String LOG_TAG = "AccessibilitySecurityPolicy";
62 
63     private static final int KEEP_SOURCE_EVENT_TYPES = AccessibilityEvent.TYPE_VIEW_CLICKED
64             | AccessibilityEvent.TYPE_VIEW_FOCUSED
65             | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER
66             | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT
67             | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED
68             | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED
69             | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED
70             | AccessibilityEvent.TYPE_WINDOWS_CHANGED
71             | AccessibilityEvent.TYPE_VIEW_SELECTED
72             | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED
73             | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED
74             | AccessibilityEvent.TYPE_VIEW_SCROLLED
75             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUSED
76             | AccessibilityEvent.TYPE_VIEW_ACCESSIBILITY_FOCUS_CLEARED
77             | AccessibilityEvent.TYPE_VIEW_TEXT_TRAVERSED_AT_MOVEMENT_GRANULARITY;
78 
79     public static final boolean POLICY_WARNING_ENABLED = true;
80 
81     /**
82      * Methods that should find their way into separate modules, but are still in AMS
83      * TODO (b/111889696): Refactoring UserState to AccessibilityUserManager.
84      */
85     public interface AccessibilityUserManager {
86         /**
87          * Returns current userId maintained in accessibility manager service
88          */
getCurrentUserIdLocked()89         int getCurrentUserIdLocked();
90         // TODO: Should include resolveProfileParentLocked, but that was already in SecurityPolicy
91     }
92 
93     private final Context mContext;
94     private final PackageManager mPackageManager;
95     private final UserManager mUserManager;
96     private final AppOpsManager mAppOpsManager;
97     private final AccessibilityUserManager mAccessibilityUserManager;
98     private final PolicyWarningUIController mPolicyWarningUIController;
99     /** All bound accessibility services which don't belong to accessibility category. */
100     private final ArraySet<ComponentName> mNonA11yCategoryServices = new ArraySet<>();
101 
102     private AppWidgetManagerInternal mAppWidgetService;
103     private AccessibilityWindowManager mAccessibilityWindowManager;
104     private int mCurrentUserId = UserHandle.USER_NULL;
105 
106     /**
107      * Constructor for AccessibilityManagerService.
108      */
AccessibilitySecurityPolicy(PolicyWarningUIController policyWarningUIController, @NonNull Context context, @NonNull AccessibilityUserManager a11yUserManager)109     public AccessibilitySecurityPolicy(PolicyWarningUIController policyWarningUIController,
110             @NonNull Context context,
111             @NonNull AccessibilityUserManager a11yUserManager) {
112         mContext = context;
113         mAccessibilityUserManager = a11yUserManager;
114         mPackageManager = mContext.getPackageManager();
115         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
116         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
117         mPolicyWarningUIController = policyWarningUIController;
118         mPolicyWarningUIController.setAccessibilityPolicyManager(this);
119     }
120 
121     /**
122      * Setup AccessibilityWindowManager. This isn't part of the constructor because the
123      * window manager and security policy both call each other.
124      */
setAccessibilityWindowManager(@onNull AccessibilityWindowManager awm)125     public void setAccessibilityWindowManager(@NonNull AccessibilityWindowManager awm) {
126         mAccessibilityWindowManager = awm;
127     }
128 
129     /**
130      * Setup AppWidgetManger during boot phase.
131      */
setAppWidgetManager(@onNull AppWidgetManagerInternal appWidgetManager)132     public void setAppWidgetManager(@NonNull AppWidgetManagerInternal appWidgetManager) {
133         mAppWidgetService = appWidgetManager;
134     }
135 
136     /**
137      * Check if an accessibility event can be dispatched. Events should be dispatched only if they
138      * are dispatched from items that services can see.
139      *
140      * @param userId The userId to check
141      * @param event The event to check
142      * @return {@code true} if the event can be dispatched
143      */
canDispatchAccessibilityEventLocked(int userId, @NonNull AccessibilityEvent event)144     public boolean canDispatchAccessibilityEventLocked(int userId,
145             @NonNull AccessibilityEvent event) {
146         final int eventType = event.getEventType();
147         switch (eventType) {
148             // All events that are for changes in a global window
149             // state should *always* be dispatched.
150             case AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED:
151             case AccessibilityEvent.TYPE_NOTIFICATION_STATE_CHANGED:
152             case AccessibilityEvent.TYPE_ANNOUNCEMENT:
153                 // All events generated by the user touching the
154                 // screen should *always* be dispatched.
155             case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_START:
156             case AccessibilityEvent.TYPE_TOUCH_EXPLORATION_GESTURE_END:
157             case AccessibilityEvent.TYPE_GESTURE_DETECTION_START:
158             case AccessibilityEvent.TYPE_GESTURE_DETECTION_END:
159             case AccessibilityEvent.TYPE_TOUCH_INTERACTION_START:
160             case AccessibilityEvent.TYPE_TOUCH_INTERACTION_END:
161             case AccessibilityEvent.TYPE_VIEW_HOVER_ENTER:
162             case AccessibilityEvent.TYPE_VIEW_HOVER_EXIT:
163                 // Also always dispatch the event that assist is reading context.
164             case AccessibilityEvent.TYPE_ASSIST_READING_CONTEXT:
165                 // Also windows changing should always be dispatched.
166             case AccessibilityEvent.TYPE_WINDOWS_CHANGED: {
167                 return true;
168             }
169             // All events for changes in window content should be
170             // dispatched *only* if this window is one of the windows
171             // the accessibility layer reports which are windows
172             // that a sighted user can touch.
173             default: {
174                 return isRetrievalAllowingWindowLocked(userId, event.getWindowId());
175             }
176         }
177     }
178 
179     /**
180      * Find a valid package name for an app to expose to accessibility
181      *
182      * @param packageName The package name the app wants to expose
183      * @param appId The app's id
184      * @param userId The app's user id
185      * @param pid The app's process pid that requested this
186      * @return A package name that is valid to report
187      */
188     @Nullable
resolveValidReportedPackageLocked( @ullable CharSequence packageName, int appId, int userId, int pid)189     public String resolveValidReportedPackageLocked(
190             @Nullable CharSequence packageName, int appId, int userId, int pid) {
191         // Okay to pass no package
192         if (packageName == null) {
193             return null;
194         }
195         // The system gets to pass any package
196         if (appId == Process.SYSTEM_UID) {
197             return packageName.toString();
198         }
199         // Passing a package in your UID is fine
200         final String packageNameStr = packageName.toString();
201         final int resolvedUid = UserHandle.getUid(userId, appId);
202         if (isValidPackageForUid(packageNameStr, resolvedUid)) {
203             return packageName.toString();
204         }
205         // Appwidget hosts get to pass packages for widgets they host
206         if (mAppWidgetService != null && ArrayUtils.contains(mAppWidgetService
207                 .getHostedWidgetPackages(resolvedUid), packageNameStr)) {
208             return packageName.toString();
209         }
210         // If app has the targeted permission to act as another package
211         if (mContext.checkPermission(Manifest.permission.ACT_AS_PACKAGE_FOR_ACCESSIBILITY,
212                 pid, resolvedUid) == PackageManager.PERMISSION_GRANTED) {
213             return packageName.toString();
214         }
215         // Otherwise, set the package to the first one in the UID
216         final String[] packageNames = mPackageManager.getPackagesForUid(resolvedUid);
217         if (ArrayUtils.isEmpty(packageNames)) {
218             return null;
219         }
220         // Okay, the caller reported a package it does not have access to.
221         // Instead of crashing the caller for better backwards compatibility
222         // we report the first package in the UID. Since most of the time apps
223         // don't use shared user id, this will yield correct results and for
224         // the edge case of using a shared user id we may report the wrong
225         // package but this is fine since first, this is a cheating app and
226         // second there is no way to get the correct package anyway.
227         return packageNames[0];
228     }
229 
230     /**
231      * Get the packages that are valid for a uid. In some situations, like app widgets, there
232      * could be several valid packages
233      *
234      * @param targetPackage A package that is known to be valid for this id
235      * @param targetUid The whose packages should be checked
236      * @return An array of all valid package names. An empty array means any package is OK
237      */
238     @NonNull
computeValidReportedPackages( @onNull String targetPackage, int targetUid)239     public String[] computeValidReportedPackages(
240             @NonNull String targetPackage, int targetUid) {
241         if (UserHandle.getAppId(targetUid) == Process.SYSTEM_UID) {
242             // Empty array means any package is Okay
243             return EmptyArray.STRING;
244         }
245         // IMPORTANT: The target package is already vetted to be in the target UID
246         String[] uidPackages = new String[]{targetPackage};
247         // Appwidget hosts get to pass packages for widgets they host
248         if (mAppWidgetService != null) {
249             final ArraySet<String> widgetPackages = mAppWidgetService
250                     .getHostedWidgetPackages(targetUid);
251             if (widgetPackages != null && !widgetPackages.isEmpty()) {
252                 final String[] validPackages = new String[uidPackages.length
253                         + widgetPackages.size()];
254                 System.arraycopy(uidPackages, 0, validPackages, 0, uidPackages.length);
255                 final int widgetPackageCount = widgetPackages.size();
256                 for (int i = 0; i < widgetPackageCount; i++) {
257                     validPackages[uidPackages.length + i] = widgetPackages.valueAt(i);
258                 }
259                 return validPackages;
260             }
261         }
262         return uidPackages;
263     }
264 
265     /**
266      * Reset the event source for events that should not carry one
267      *
268      * @param event The event potentially to modify
269      */
updateEventSourceLocked(@onNull AccessibilityEvent event)270     public void updateEventSourceLocked(@NonNull AccessibilityEvent event) {
271         if ((event.getEventType() & KEEP_SOURCE_EVENT_TYPES) == 0) {
272             event.setSource(null);
273         }
274     }
275 
276     /**
277      * Check if a service can have access to a window
278      *
279      * @param userId The id of the user running the service
280      * @param service The service requesting access
281      * @param windowId The window it wants access to
282      *
283      * @return Whether ot not the service may retrieve info from the window
284      */
canGetAccessibilityNodeInfoLocked(int userId, @NonNull AbstractAccessibilityServiceConnection service, int windowId)285     public boolean canGetAccessibilityNodeInfoLocked(int userId,
286             @NonNull AbstractAccessibilityServiceConnection service, int windowId) {
287         return canRetrieveWindowContentLocked(service)
288                 && isRetrievalAllowingWindowLocked(userId, windowId);
289     }
290 
291     /**
292      * Check if a service can have access the list of windows
293      *
294      * @param service The service requesting access
295      *
296      * @return Whether ot not the service may retrieve the window list
297      */
canRetrieveWindowsLocked( @onNull AbstractAccessibilityServiceConnection service)298     public boolean canRetrieveWindowsLocked(
299             @NonNull AbstractAccessibilityServiceConnection service) {
300         return canRetrieveWindowContentLocked(service) && service.mRetrieveInteractiveWindows;
301     }
302 
303     /**
304      * Check if a service can have access the content of windows on the screen
305      *
306      * @param service The service requesting access
307      *
308      * @return Whether ot not the service may retrieve the content
309      */
canRetrieveWindowContentLocked( @onNull AbstractAccessibilityServiceConnection service)310     public boolean canRetrieveWindowContentLocked(
311             @NonNull AbstractAccessibilityServiceConnection service) {
312         return (service.getCapabilities()
313                 & AccessibilityServiceInfo.CAPABILITY_CAN_RETRIEVE_WINDOW_CONTENT) != 0;
314     }
315 
316     /**
317      * Check if a service can control magnification
318      *
319      * @param service The service requesting access
320      *
321      * @return Whether ot not the service may control magnification
322      */
canControlMagnification( @onNull AbstractAccessibilityServiceConnection service)323     public boolean canControlMagnification(
324             @NonNull AbstractAccessibilityServiceConnection service) {
325         return (service.getCapabilities()
326                 & AccessibilityServiceInfo.CAPABILITY_CAN_CONTROL_MAGNIFICATION) != 0;
327     }
328 
329     /**
330      * Check if a service can perform gestures
331      *
332      * @param service The service requesting access
333      *
334      * @return Whether ot not the service may perform gestures
335      */
canPerformGestures(@onNull AccessibilityServiceConnection service)336     public boolean canPerformGestures(@NonNull AccessibilityServiceConnection service) {
337         return (service.getCapabilities()
338                 & AccessibilityServiceInfo.CAPABILITY_CAN_PERFORM_GESTURES) != 0;
339     }
340 
341     /**
342      * Check if a service can capture gestures from the fingerprint sensor
343      *
344      * @param service The service requesting access
345      *
346      * @return Whether ot not the service may capture gestures from the fingerprint sensor
347      */
canCaptureFingerprintGestures(@onNull AccessibilityServiceConnection service)348     public boolean canCaptureFingerprintGestures(@NonNull AccessibilityServiceConnection service) {
349         return (service.getCapabilities()
350                 & AccessibilityServiceInfo.CAPABILITY_CAN_REQUEST_FINGERPRINT_GESTURES) != 0;
351     }
352 
353     /**
354      * Checks if a service can take screenshot.
355      *
356      * @param service The service requesting access
357      *
358      * @return Whether ot not the service may take screenshot
359      */
canTakeScreenshotLocked( @onNull AbstractAccessibilityServiceConnection service)360     public boolean canTakeScreenshotLocked(
361             @NonNull AbstractAccessibilityServiceConnection service) {
362         return (service.getCapabilities()
363                 & AccessibilityServiceInfo.CAPABILITY_CAN_TAKE_SCREENSHOT) != 0;
364     }
365 
366     /**
367      * Returns the parent userId of the profile according to the specified userId.
368      *
369      * @param userId The userId to check
370      * @return the parent userId of the profile, or self if no parent exist
371      */
resolveProfileParentLocked(int userId)372     public int resolveProfileParentLocked(int userId) {
373         if (userId != mAccessibilityUserManager.getCurrentUserIdLocked()) {
374             final long identity = Binder.clearCallingIdentity();
375             try {
376                 UserInfo parent = mUserManager.getProfileParent(userId);
377                 if (parent != null) {
378                     return parent.getUserHandle().getIdentifier();
379                 }
380             } finally {
381                 Binder.restoreCallingIdentity(identity);
382             }
383         }
384         return userId;
385     }
386 
387     /**
388      * Returns the parent userId of the profile according to the specified userId. Enforcing
389      * permissions check if specified userId is not caller's userId.
390      *
391      * @param userId The userId to check
392      * @return the parent userId of the profile, or self if no parent exist
393      * @throws SecurityException if caller cannot interact across users
394      * @throws IllegalArgumentException if specified invalid userId
395      */
resolveCallingUserIdEnforcingPermissionsLocked(int userId)396     public int resolveCallingUserIdEnforcingPermissionsLocked(int userId) {
397         final int callingUid = Binder.getCallingUid();
398         final int currentUserId = mAccessibilityUserManager.getCurrentUserIdLocked();
399         if (callingUid == 0
400                 || callingUid == Process.SYSTEM_UID
401                 || callingUid == Process.SHELL_UID) {
402             if (userId == UserHandle.USER_CURRENT
403                     || userId == UserHandle.USER_CURRENT_OR_SELF) {
404                 return currentUserId;
405             }
406             return resolveProfileParentLocked(userId);
407         }
408         final int callingUserId = UserHandle.getUserId(callingUid);
409         if (callingUserId == userId) {
410             return resolveProfileParentLocked(userId);
411         }
412         final int callingUserParentId = resolveProfileParentLocked(callingUserId);
413         if (callingUserParentId == currentUserId && (userId == UserHandle.USER_CURRENT
414                 || userId == UserHandle.USER_CURRENT_OR_SELF)) {
415             return currentUserId;
416         }
417         if (!hasPermission(Manifest.permission.INTERACT_ACROSS_USERS)
418                 && !hasPermission(Manifest.permission.INTERACT_ACROSS_USERS_FULL)) {
419             throw new SecurityException("Call from user " + callingUserId + " as user "
420                     + userId + " without permission INTERACT_ACROSS_USERS or "
421                     + "INTERACT_ACROSS_USERS_FULL not allowed.");
422         }
423         if (userId == UserHandle.USER_CURRENT
424                 || userId == UserHandle.USER_CURRENT_OR_SELF) {
425             return currentUserId;
426         }
427         return resolveProfileParentLocked(userId);
428     }
429 
430     /**
431      * Returns false if caller is not SYSTEM and SHELL, and tried to interact across users.
432      *
433      * @param userId The userId to interact.
434      * @return false if caller cannot interact across users.
435      */
isCallerInteractingAcrossUsers(int userId)436     public boolean isCallerInteractingAcrossUsers(int userId) {
437         final int callingUid = Binder.getCallingUid();
438         return (Binder.getCallingPid() == android.os.Process.myPid()
439                 || callingUid == Process.SHELL_UID
440                 || userId == UserHandle.USER_CURRENT
441                 || userId == UserHandle.USER_CURRENT_OR_SELF);
442     }
443 
isValidPackageForUid(String packageName, int uid)444     private boolean isValidPackageForUid(String packageName, int uid) {
445         final long token = Binder.clearCallingIdentity();
446         try {
447             return uid == mPackageManager.getPackageUidAsUser(
448                     packageName, UserHandle.getUserId(uid));
449         } catch (PackageManager.NameNotFoundException e) {
450             return false;
451         } finally {
452             Binder.restoreCallingIdentity(token);
453         }
454     }
455 
isRetrievalAllowingWindowLocked(int userId, int windowId)456     private boolean isRetrievalAllowingWindowLocked(int userId, int windowId) {
457         // The system gets to interact with any window it wants.
458         if (Binder.getCallingUid() == Process.SYSTEM_UID) {
459             return true;
460         }
461         if (Binder.getCallingUid() == Process.SHELL_UID) {
462             if (!isShellAllowedToRetrieveWindowLocked(userId, windowId)) {
463                 return false;
464             }
465         }
466         if (mAccessibilityWindowManager.resolveParentWindowIdLocked(windowId)
467                 == mAccessibilityWindowManager.getActiveWindowId(userId)) {
468             return true;
469         }
470         return mAccessibilityWindowManager.findA11yWindowInfoByIdLocked(windowId) != null;
471     }
472 
isShellAllowedToRetrieveWindowLocked(int userId, int windowId)473     private boolean isShellAllowedToRetrieveWindowLocked(int userId, int windowId) {
474         final long token = Binder.clearCallingIdentity();
475         try {
476             IBinder windowToken = mAccessibilityWindowManager
477                     .getWindowTokenForUserAndWindowIdLocked(userId, windowId);
478             if (windowToken == null) {
479                 return false;
480             }
481             int windowOwnerUserId = mAccessibilityWindowManager.getWindowOwnerUserId(windowToken);
482             if (windowOwnerUserId == UserHandle.USER_NULL) {
483                 return false;
484             }
485             return !mUserManager.hasUserRestriction(
486                     UserManager.DISALLOW_DEBUGGING_FEATURES, UserHandle.of(windowOwnerUserId));
487         } finally {
488             Binder.restoreCallingIdentity(token);
489         }
490     }
491 
492     /**
493      * Enforcing permission check to caller.
494      *
495      * @param permission The permission to check
496      * @param function The function name to check
497      */
enforceCallingPermission(@onNull String permission, @Nullable String function)498     public void enforceCallingPermission(@NonNull String permission, @Nullable String function) {
499         if (OWN_PROCESS_ID == Binder.getCallingPid()) {
500             return;
501         }
502         if (!hasPermission(permission)) {
503             throw new SecurityException("You do not have " + permission
504                     + " required to call " + function + " from pid="
505                     + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid());
506         }
507     }
508 
509     /**
510      * Permission check to caller.
511      *
512      * @param permission The permission to check
513      * @return true if caller has permission
514      */
hasPermission(@onNull String permission)515     public boolean hasPermission(@NonNull String permission) {
516         return mContext.checkCallingPermission(permission) == PackageManager.PERMISSION_GRANTED;
517     }
518 
519     /**
520      * Checks if accessibility service could register into the system.
521      *
522      * @param serviceInfo The ServiceInfo
523      * @return True if it could register into the system
524      */
canRegisterService(@onNull ServiceInfo serviceInfo)525     public boolean canRegisterService(@NonNull ServiceInfo serviceInfo) {
526         if (!android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE.equals(
527                 serviceInfo.permission)) {
528             Slog.w(LOG_TAG, "Skipping accessibility service " + new ComponentName(
529                     serviceInfo.packageName, serviceInfo.name).flattenToShortString()
530                     + ": it does not require the permission "
531                     + android.Manifest.permission.BIND_ACCESSIBILITY_SERVICE);
532             return false;
533         }
534 
535         int servicePackageUid = serviceInfo.applicationInfo.uid;
536         if (mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_BIND_ACCESSIBILITY_SERVICE,
537                 servicePackageUid, serviceInfo.packageName) != AppOpsManager.MODE_ALLOWED) {
538             Slog.w(LOG_TAG, "Skipping accessibility service " + new ComponentName(
539                     serviceInfo.packageName, serviceInfo.name).flattenToShortString()
540                     + ": disallowed by AppOps");
541             return false;
542         }
543 
544         return true;
545     }
546 
547     /**
548      * Checks if accessibility service could execute accessibility operations.
549      *
550      * @param service The accessibility service connection
551      * @return True if it could execute accessibility operations
552      */
checkAccessibilityAccess(AbstractAccessibilityServiceConnection service)553     public boolean checkAccessibilityAccess(AbstractAccessibilityServiceConnection service) {
554         final String packageName = service.getComponentName().getPackageName();
555         final ResolveInfo resolveInfo = service.getServiceInfo().getResolveInfo();
556 
557         if (resolveInfo == null) {
558             // For InteractionBridge and UiAutomation
559             return true;
560         }
561 
562         final int uid = resolveInfo.serviceInfo.applicationInfo.uid;
563         final long identityToken = Binder.clearCallingIdentity();
564         try {
565             // For the caller is system, just block the data to a11y services.
566             if (OWN_PROCESS_ID == Binder.getCallingPid()) {
567                 return mAppOpsManager.noteOpNoThrow(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY,
568                         uid, packageName) == AppOpsManager.MODE_ALLOWED;
569             }
570 
571             return mAppOpsManager.noteOp(AppOpsManager.OPSTR_ACCESS_ACCESSIBILITY,
572                     uid, packageName) == AppOpsManager.MODE_ALLOWED;
573         } finally {
574             Binder.restoreCallingIdentity(identityToken);
575         }
576     }
577 
578     /**
579      * Enforcing permission check to IPC caller or grant it if it's not through IPC.
580      *
581      * @param permission The permission to check
582      */
enforceCallingOrSelfPermission(@onNull String permission)583     public void enforceCallingOrSelfPermission(@NonNull String permission) {
584         if (mContext.checkCallingOrSelfPermission(permission)
585                 != PackageManager.PERMISSION_GRANTED) {
586             throw new SecurityException("Caller does not hold permission "
587                     + permission);
588         }
589     }
590 
591     /**
592      * Called after a service was bound or unbound. Checks the current bound accessibility
593      * services and updates alarms.
594      *
595      * @param userId        The user id
596      * @param boundServices The bound services
597      */
onBoundServicesChangedLocked(int userId, ArrayList<AccessibilityServiceConnection> boundServices)598     public void onBoundServicesChangedLocked(int userId,
599             ArrayList<AccessibilityServiceConnection> boundServices) {
600         if (!POLICY_WARNING_ENABLED) {
601             return;
602         }
603         if (mAccessibilityUserManager.getCurrentUserIdLocked() != userId) {
604             return;
605         }
606 
607         ArraySet<ComponentName> tempNonA11yCategoryServices = new ArraySet<>();
608         for (int i = 0; i < boundServices.size(); i++) {
609             final AccessibilityServiceInfo a11yServiceInfo = boundServices.get(
610                     i).getServiceInfo();
611             final ComponentName service = a11yServiceInfo.getComponentName().clone();
612             if (!isA11yCategoryService(a11yServiceInfo)) {
613                 tempNonA11yCategoryServices.add(service);
614                 if (mNonA11yCategoryServices.contains(service)) {
615                     mNonA11yCategoryServices.remove(service);
616                 } else {
617                     mPolicyWarningUIController.onNonA11yCategoryServiceBound(userId, service);
618                 }
619             }
620         }
621 
622         for (int i = 0; i < mNonA11yCategoryServices.size(); i++) {
623             final ComponentName service = mNonA11yCategoryServices.valueAt(i);
624             mPolicyWarningUIController.onNonA11yCategoryServiceUnbound(userId, service);
625         }
626         mNonA11yCategoryServices.clear();
627         mNonA11yCategoryServices.addAll(tempNonA11yCategoryServices);
628     }
629 
630     /**
631      * Called after switching to another user. Resets data and cancels old alarms after
632      * switching to another user.
633      *
634      * @param userId          The user id
635      * @param enabledServices The enabled services
636      */
onSwitchUserLocked(int userId, Set<ComponentName> enabledServices)637     public void onSwitchUserLocked(int userId, Set<ComponentName> enabledServices) {
638         if (!POLICY_WARNING_ENABLED) {
639             return;
640         }
641         if (mCurrentUserId == userId) {
642             return;
643         }
644 
645         mPolicyWarningUIController.onSwitchUserLocked(userId, enabledServices);
646 
647         for (int i = 0; i < mNonA11yCategoryServices.size(); i++) {
648             mPolicyWarningUIController.onNonA11yCategoryServiceUnbound(mCurrentUserId,
649                     mNonA11yCategoryServices.valueAt(i));
650         }
651         mNonA11yCategoryServices.clear();
652         mCurrentUserId = userId;
653     }
654 
655     /**
656      * Called after the enabled accessibility services changed.
657      *
658      * @param userId          The user id
659      * @param enabledServices The enabled services
660      */
onEnabledServicesChangedLocked(int userId, Set<ComponentName> enabledServices)661     public void onEnabledServicesChangedLocked(int userId,
662             Set<ComponentName> enabledServices) {
663         if (!POLICY_WARNING_ENABLED) {
664             return;
665         }
666         if (mAccessibilityUserManager.getCurrentUserIdLocked() != userId) {
667             return;
668         }
669 
670         mPolicyWarningUIController.onEnabledServicesChangedLocked(userId, enabledServices);
671     }
672 
673     /**
674      * Identifies whether the accessibility service is true and designed for accessibility. An
675      * accessibility service is considered as accessibility category if meets all conditions below:
676      * <ul>
677      *     <li> {@link AccessibilityServiceInfo#isAccessibilityTool} is true</li>
678      *     <li> is installed from the trusted install source</li>
679      * </ul>
680      *
681      * @param serviceInfo The accessibility service's serviceInfo.
682      * @return Returns true if it is a true accessibility service.
683      */
isA11yCategoryService(AccessibilityServiceInfo serviceInfo)684     public boolean isA11yCategoryService(AccessibilityServiceInfo serviceInfo) {
685         if (!serviceInfo.isAccessibilityTool()) {
686             return false;
687         }
688         if (!serviceInfo.getResolveInfo().serviceInfo.applicationInfo.isSystemApp()) {
689             return hasTrustedSystemInstallSource(
690                     serviceInfo.getResolveInfo().serviceInfo.packageName);
691         }
692         return true;
693     }
694 
695     /** Returns true if the {@code installedPackage} is installed from the trusted install source.
696      */
hasTrustedSystemInstallSource(String installedPackage)697     private boolean hasTrustedSystemInstallSource(String installedPackage) {
698         try {
699             InstallSourceInfo installSourceInfo = mPackageManager.getInstallSourceInfo(
700                     installedPackage);
701             if (installSourceInfo == null) {
702                 return false;
703             }
704             final String installSourcePackageName = installSourceInfo.getInitiatingPackageName();
705             if (installSourcePackageName == null || !mPackageManager.getPackageInfo(
706                     installSourcePackageName,
707                     0).applicationInfo.isSystemApp()) {
708                 return false;
709             }
710             return isTrustedInstallSource(installSourcePackageName);
711         } catch (PackageManager.NameNotFoundException e) {
712             Slog.w(LOG_TAG, "can't find the package's install source:" + installedPackage);
713         }
714         return false;
715     }
716 
717     /** Returns true if the {@code installerPackage} is a trusted install source. */
isTrustedInstallSource(String installerPackage)718     private boolean isTrustedInstallSource(String installerPackage) {
719         final String[] allowedInstallingSources = mContext.getResources().getStringArray(
720                 com.android.internal.R.array
721                         .config_accessibility_allowed_install_source);
722 
723         if (allowedInstallingSources.length == 0) {
724             //Filters unwanted default installers if no allowed install sources.
725             String defaultInstaller = ArrayUtils.firstOrNull(LocalServices.getService(
726                     PackageManagerInternal.class).getKnownPackageNames(PACKAGE_INSTALLER,
727                     mCurrentUserId));
728             return !TextUtils.equals(defaultInstaller, installerPackage);
729         }
730         for (int i = 0; i < allowedInstallingSources.length; i++) {
731             if (TextUtils.equals(allowedInstallingSources[i], installerPackage)) {
732                 return true;
733             }
734         }
735         return false;
736     }
737 }
738