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