1/* 2 ** Copyright 2009, 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 17package com.android.server.accessibility; 18 19import android.Manifest; 20import android.accessibilityservice.AccessibilityService; 21import android.accessibilityservice.AccessibilityServiceInfo; 22import android.accessibilityservice.IAccessibilityServiceConnection; 23import android.accessibilityservice.IEventListener; 24import android.app.PendingIntent; 25import android.content.BroadcastReceiver; 26import android.content.ComponentName; 27import android.content.ContentResolver; 28import android.content.Context; 29import android.content.Intent; 30import android.content.IntentFilter; 31import android.content.ServiceConnection; 32import android.content.pm.PackageManager; 33import android.content.pm.ResolveInfo; 34import android.database.ContentObserver; 35import android.graphics.Rect; 36import android.net.Uri; 37import android.os.Binder; 38import android.os.Handler; 39import android.os.IBinder; 40import android.os.Message; 41import android.os.RemoteException; 42import android.os.ServiceManager; 43import android.provider.Settings; 44import android.text.TextUtils; 45import android.text.TextUtils.SimpleStringSplitter; 46import android.util.Slog; 47import android.util.SparseArray; 48import android.view.IWindow; 49import android.view.View; 50import android.view.accessibility.AccessibilityEvent; 51import android.view.accessibility.AccessibilityManager; 52import android.view.accessibility.AccessibilityNodeInfo; 53import android.view.accessibility.IAccessibilityInteractionConnection; 54import android.view.accessibility.IAccessibilityInteractionConnectionCallback; 55import android.view.accessibility.IAccessibilityManager; 56import android.view.accessibility.IAccessibilityManagerClient; 57 58import com.android.internal.content.PackageMonitor; 59import com.android.internal.os.HandlerCaller; 60import com.android.internal.os.HandlerCaller.SomeArgs; 61import com.android.server.wm.WindowManagerService; 62 63import org.xmlpull.v1.XmlPullParserException; 64 65import java.io.IOException; 66import java.util.ArrayList; 67import java.util.Arrays; 68import java.util.HashMap; 69import java.util.HashSet; 70import java.util.Iterator; 71import java.util.List; 72import java.util.Map; 73import java.util.Set; 74 75/** 76 * This class is instantiated by the system as a system level service and can be 77 * accessed only by the system. The task of this service is to be a centralized 78 * event dispatch for {@link AccessibilityEvent}s generated across all processes 79 * on the device. Events are dispatched to {@link AccessibilityService}s. 80 * 81 * @hide 82 */ 83public class AccessibilityManagerService extends IAccessibilityManager.Stub 84 implements HandlerCaller.Callback { 85 86 private static final boolean DEBUG = false; 87 88 private static final String LOG_TAG = "AccessibilityManagerService"; 89 90 private static final String FUNCTION_REGISTER_EVENT_LISTENER = 91 "registerEventListener"; 92 93 private static int sIdCounter = 0; 94 95 private static final int OWN_PROCESS_ID = android.os.Process.myPid(); 96 97 private static final int DO_SET_SERVICE_INFO = 10; 98 99 private static int sNextWindowId; 100 101 final HandlerCaller mCaller; 102 103 final Context mContext; 104 105 final Object mLock = new Object(); 106 107 final List<Service> mServices = new ArrayList<Service>(); 108 109 final List<IAccessibilityManagerClient> mClients = 110 new ArrayList<IAccessibilityManagerClient>(); 111 112 final Map<ComponentName, Service> mComponentNameToServiceMap = new HashMap<ComponentName, Service>(); 113 114 private final List<AccessibilityServiceInfo> mInstalledServices = new ArrayList<AccessibilityServiceInfo>(); 115 116 private final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>(); 117 118 private final SparseArray<AccessibilityConnectionWrapper> mWindowIdToInteractionConnectionWrapperMap = 119 new SparseArray<AccessibilityConnectionWrapper>(); 120 121 private final SparseArray<IBinder> mWindowIdToWindowTokenMap = new SparseArray<IBinder>(); 122 123 private final SimpleStringSplitter mStringColonSplitter = new SimpleStringSplitter(':'); 124 125 private PackageManager mPackageManager; 126 127 private int mHandledFeedbackTypes = 0; 128 129 private boolean mIsAccessibilityEnabled; 130 131 private AccessibilityInputFilter mInputFilter; 132 133 private boolean mHasInputFilter; 134 135 private final List<AccessibilityServiceInfo> mEnabledServicesForFeedbackTempList = new ArrayList<AccessibilityServiceInfo>(); 136 137 private boolean mIsTouchExplorationEnabled; 138 139 private final WindowManagerService mWindowManagerService; 140 141 private final SecurityPolicy mSecurityPolicy; 142 143 /** 144 * Handler for delayed event dispatch. 145 */ 146 private Handler mHandler = new Handler() { 147 148 @Override 149 public void handleMessage(Message message) { 150 Service service = (Service) message.obj; 151 int eventType = message.arg1; 152 153 synchronized (mLock) { 154 notifyEventListenerLocked(service, eventType); 155 } 156 } 157 }; 158 159 /** 160 * Creates a new instance. 161 * 162 * @param context A {@link Context} instance. 163 */ 164 public AccessibilityManagerService(Context context) { 165 mContext = context; 166 mPackageManager = mContext.getPackageManager(); 167 mCaller = new HandlerCaller(context, this); 168 mWindowManagerService = (WindowManagerService) ServiceManager.getService( 169 Context.WINDOW_SERVICE); 170 mSecurityPolicy = new SecurityPolicy(); 171 172 registerPackageChangeAndBootCompletedBroadcastReceiver(); 173 registerSettingsContentObservers(); 174 } 175 176 /** 177 * Registers a {@link BroadcastReceiver} for the events of 178 * adding/changing/removing/restarting a package and boot completion. 179 */ 180 private void registerPackageChangeAndBootCompletedBroadcastReceiver() { 181 Context context = mContext; 182 183 PackageMonitor monitor = new PackageMonitor() { 184 @Override 185 public void onSomePackagesChanged() { 186 synchronized (mLock) { 187 populateAccessibilityServiceListLocked(); 188 manageServicesLocked(); 189 } 190 } 191 192 @Override 193 public void onPackageRemoved(String packageName, int uid) { 194 synchronized (mLock) { 195 Iterator<ComponentName> it = mEnabledServices.iterator(); 196 while (it.hasNext()) { 197 ComponentName comp = it.next(); 198 String compPkg = comp.getPackageName(); 199 if (compPkg.equals(packageName)) { 200 it.remove(); 201 updateEnabledAccessibilitySerivcesSettingLocked(mEnabledServices); 202 return; 203 } 204 } 205 } 206 } 207 208 @Override 209 public boolean onHandleForceStop(Intent intent, String[] packages, 210 int uid, boolean doit) { 211 synchronized (mLock) { 212 boolean changed = false; 213 Iterator<ComponentName> it = mEnabledServices.iterator(); 214 while (it.hasNext()) { 215 ComponentName comp = it.next(); 216 String compPkg = comp.getPackageName(); 217 for (String pkg : packages) { 218 if (compPkg.equals(pkg)) { 219 if (!doit) { 220 return true; 221 } 222 it.remove(); 223 changed = true; 224 } 225 } 226 } 227 if (changed) { 228 updateEnabledAccessibilitySerivcesSettingLocked(mEnabledServices); 229 } 230 return false; 231 } 232 } 233 234 @Override 235 public void onReceive(Context context, Intent intent) { 236 if (intent.getAction() == Intent.ACTION_BOOT_COMPLETED) { 237 synchronized (mLock) { 238 populateAccessibilityServiceListLocked(); 239 // get accessibility enabled setting on boot 240 mIsAccessibilityEnabled = Settings.Secure.getInt( 241 mContext.getContentResolver(), 242 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1; 243 244 manageServicesLocked(); 245 246 // get touch exploration enabled setting on boot 247 mIsTouchExplorationEnabled = Settings.Secure.getInt( 248 mContext.getContentResolver(), 249 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1; 250 updateInputFilterLocked(); 251 252 sendStateToClientsLocked(); 253 } 254 255 return; 256 } 257 258 super.onReceive(context, intent); 259 } 260 261 private void updateEnabledAccessibilitySerivcesSettingLocked( 262 Set<ComponentName> enabledServices) { 263 Iterator<ComponentName> it = enabledServices.iterator(); 264 StringBuilder str = new StringBuilder(); 265 while (it.hasNext()) { 266 if (str.length() > 0) { 267 str.append(':'); 268 } 269 str.append(it.next().flattenToShortString()); 270 } 271 Settings.Secure.putString(mContext.getContentResolver(), 272 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES, 273 str.toString()); 274 } 275 }; 276 277 // package changes 278 monitor.register(context, true); 279 280 // boot completed 281 IntentFilter bootFiler = new IntentFilter(Intent.ACTION_BOOT_COMPLETED); 282 mContext.registerReceiver(monitor, bootFiler); 283 } 284 285 /** 286 * {@link ContentObserver}s for {@link Settings.Secure#ACCESSIBILITY_ENABLED} 287 * and {@link Settings.Secure#ENABLED_ACCESSIBILITY_SERVICES} settings. 288 */ 289 private void registerSettingsContentObservers() { 290 ContentResolver contentResolver = mContext.getContentResolver(); 291 292 Uri accessibilityEnabledUri = Settings.Secure.getUriFor( 293 Settings.Secure.ACCESSIBILITY_ENABLED); 294 contentResolver.registerContentObserver(accessibilityEnabledUri, false, 295 new ContentObserver(new Handler()) { 296 @Override 297 public void onChange(boolean selfChange) { 298 super.onChange(selfChange); 299 300 synchronized (mLock) { 301 handleAccessibilityEnabledSettingChangedLocked(); 302 } 303 } 304 }); 305 306 Uri touchExplorationRequestedUri = Settings.Secure.getUriFor( 307 Settings.Secure.TOUCH_EXPLORATION_ENABLED); 308 contentResolver.registerContentObserver(touchExplorationRequestedUri, false, 309 new ContentObserver(new Handler()) { 310 @Override 311 public void onChange(boolean selfChange) { 312 super.onChange(selfChange); 313 314 synchronized (mLock) { 315 mIsTouchExplorationEnabled = Settings.Secure.getInt( 316 mContext.getContentResolver(), 317 Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0) == 1; 318 updateInputFilterLocked(); 319 sendStateToClientsLocked(); 320 } 321 } 322 }); 323 324 Uri accessibilityServicesUri = 325 Settings.Secure.getUriFor(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 326 contentResolver.registerContentObserver(accessibilityServicesUri, false, 327 new ContentObserver(new Handler()) { 328 @Override 329 public void onChange(boolean selfChange) { 330 super.onChange(selfChange); 331 332 synchronized (mLock) { 333 manageServicesLocked(); 334 } 335 } 336 }); 337 } 338 339 public int addClient(IAccessibilityManagerClient client) throws RemoteException { 340 synchronized (mLock) { 341 final IAccessibilityManagerClient addedClient = client; 342 mClients.add(addedClient); 343 // Clients are registered all the time until their process is 344 // killed, therefore we do not have a corresponding unlinkToDeath. 345 client.asBinder().linkToDeath(new DeathRecipient() { 346 public void binderDied() { 347 synchronized (mLock) { 348 addedClient.asBinder().unlinkToDeath(this, 0); 349 mClients.remove(addedClient); 350 } 351 } 352 }, 0); 353 return getState(); 354 } 355 } 356 357 public boolean sendAccessibilityEvent(AccessibilityEvent event) { 358 synchronized (mLock) { 359 if (mSecurityPolicy.canDispatchAccessibilityEvent(event)) { 360 mSecurityPolicy.updateRetrievalAllowingWindowAndEventSourceLocked(event); 361 notifyAccessibilityServicesDelayedLocked(event, false); 362 notifyAccessibilityServicesDelayedLocked(event, true); 363 } 364 } 365 event.recycle(); 366 mHandledFeedbackTypes = 0; 367 return (OWN_PROCESS_ID != Binder.getCallingPid()); 368 } 369 370 public List<AccessibilityServiceInfo> getInstalledAccessibilityServiceList() { 371 synchronized (mLock) { 372 return mInstalledServices; 373 } 374 } 375 376 public List<AccessibilityServiceInfo> getEnabledAccessibilityServiceList(int feedbackType) { 377 List<AccessibilityServiceInfo> result = mEnabledServicesForFeedbackTempList; 378 result.clear(); 379 List<Service> services = mServices; 380 synchronized (mLock) { 381 while (feedbackType != 0) { 382 final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType)); 383 feedbackType &= ~feedbackTypeBit; 384 final int serviceCount = services.size(); 385 for (int i = 0; i < serviceCount; i++) { 386 Service service = services.get(i); 387 if ((service.mFeedbackType & feedbackTypeBit) != 0) { 388 result.add(service.mAccessibilityServiceInfo); 389 } 390 } 391 } 392 } 393 return result; 394 } 395 396 public void interrupt() { 397 synchronized (mLock) { 398 for (int i = 0, count = mServices.size(); i < count; i++) { 399 Service service = mServices.get(i); 400 try { 401 service.mServiceInterface.onInterrupt(); 402 } catch (RemoteException re) { 403 Slog.e(LOG_TAG, "Error during sending interrupt request to " 404 + service.mService, re); 405 } 406 } 407 } 408 } 409 410 public void executeMessage(Message message) { 411 switch (message.what) { 412 case DO_SET_SERVICE_INFO: { 413 SomeArgs arguments = ((SomeArgs) message.obj); 414 415 AccessibilityServiceInfo info = (AccessibilityServiceInfo) arguments.arg1; 416 Service service = (Service) arguments.arg2; 417 418 synchronized (mLock) { 419 // If the XML manifest had data to configure the service its info 420 // should be already set. In such a case update only the dynamically 421 // configurable properties. 422 AccessibilityServiceInfo oldInfo = service.mAccessibilityServiceInfo; 423 if (oldInfo != null) { 424 oldInfo.updateDynamicallyConfigurableProperties(info); 425 service.setDynamicallyConfigurableProperties(oldInfo); 426 } else { 427 service.setDynamicallyConfigurableProperties(info); 428 } 429 } 430 } return; 431 default: 432 Slog.w(LOG_TAG, "Unknown message type: " + message.what); 433 } 434 } 435 436 public int addAccessibilityInteractionConnection(IWindow windowToken, 437 IAccessibilityInteractionConnection connection) throws RemoteException { 438 synchronized (mLock) { 439 final IWindow addedWindowToken = windowToken; 440 final IAccessibilityInteractionConnection addedConnection = connection; 441 final int windowId = sNextWindowId++; 442 AccessibilityConnectionWrapper wrapper = new AccessibilityConnectionWrapper(windowId, 443 connection); 444 wrapper.linkToDeath(); 445 mWindowIdToWindowTokenMap.put(windowId, addedWindowToken.asBinder()); 446 mWindowIdToInteractionConnectionWrapperMap.put(windowId, wrapper); 447 if (DEBUG) { 448 Slog.i(LOG_TAG, "Adding interaction connection to windowId: " + windowId); 449 } 450 return windowId; 451 } 452 } 453 454 public void removeAccessibilityInteractionConnection(IWindow windowToken) { 455 synchronized (mLock) { 456 final int count = mWindowIdToWindowTokenMap.size(); 457 for (int i = 0; i < count; i++) { 458 if (mWindowIdToWindowTokenMap.valueAt(i) == windowToken.asBinder()) { 459 final int windowId = mWindowIdToWindowTokenMap.keyAt(i); 460 AccessibilityConnectionWrapper wrapper = 461 mWindowIdToInteractionConnectionWrapperMap.get(windowId); 462 wrapper.unlinkToDeath(); 463 removeAccessibilityInteractionConnectionLocked(windowId); 464 return; 465 } 466 } 467 } 468 } 469 470 public void registerEventListener(IEventListener listener) { 471 mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT, 472 FUNCTION_REGISTER_EVENT_LISTENER); 473 ComponentName componentName = new ComponentName("foo.bar", 474 "AutomationAccessibilityService"); 475 synchronized (mLock) { 476 // If an automation services is connected to the system all services are stopped 477 // so the automation one is the only one running. Settings are not changed so when 478 // the automation service goes away the state is restored from the settings. 479 480 // Disable all services. 481 final int runningServiceCount = mServices.size(); 482 for (int i = 0; i < runningServiceCount; i++) { 483 Service runningService = mServices.get(i); 484 runningService.unbind(); 485 } 486 // If necessary enable accessibility and announce that. 487 if (!mIsAccessibilityEnabled) { 488 mIsAccessibilityEnabled = true; 489 sendStateToClientsLocked(); 490 } 491 } 492 // Hook the automation service up. 493 AccessibilityServiceInfo accessibilityServiceInfo = new AccessibilityServiceInfo(); 494 accessibilityServiceInfo.eventTypes = AccessibilityEvent.TYPES_ALL_MASK; 495 accessibilityServiceInfo.feedbackType = AccessibilityServiceInfo.FEEDBACK_GENERIC; 496 Service service = new Service(componentName, accessibilityServiceInfo, true); 497 service.onServiceConnected(componentName, listener.asBinder()); 498 } 499 500 /** 501 * Removes an AccessibilityInteractionConnection. 502 * 503 * @param windowId The id of the window to which the connection is targeted. 504 */ 505 private void removeAccessibilityInteractionConnectionLocked(int windowId) { 506 mWindowIdToWindowTokenMap.remove(windowId); 507 mWindowIdToInteractionConnectionWrapperMap.remove(windowId); 508 if (DEBUG) { 509 Slog.i(LOG_TAG, "Removing interaction connection to windowId: " + windowId); 510 } 511 } 512 513 /** 514 * Populates the cached list of installed {@link AccessibilityService}s. 515 */ 516 private void populateAccessibilityServiceListLocked() { 517 mInstalledServices.clear(); 518 519 List<ResolveInfo> installedServices = mPackageManager.queryIntentServices( 520 new Intent(AccessibilityService.SERVICE_INTERFACE), 521 PackageManager.GET_SERVICES | PackageManager.GET_META_DATA); 522 523 for (int i = 0, count = installedServices.size(); i < count; i++) { 524 ResolveInfo resolveInfo = installedServices.get(i); 525 AccessibilityServiceInfo accessibilityServiceInfo; 526 try { 527 accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext); 528 mInstalledServices.add(accessibilityServiceInfo); 529 } catch (XmlPullParserException xppe) { 530 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe); 531 } catch (IOException ioe) { 532 Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe); 533 } 534 } 535 } 536 537 /** 538 * Performs {@link AccessibilityService}s delayed notification. The delay is configurable 539 * and denotes the period after the last event before notifying the service. 540 * 541 * @param event The event. 542 * @param isDefault True to notify default listeners, not default services. 543 */ 544 private void notifyAccessibilityServicesDelayedLocked(AccessibilityEvent event, 545 boolean isDefault) { 546 try { 547 for (int i = 0, count = mServices.size(); i < count; i++) { 548 Service service = mServices.get(i); 549 550 if (service.mIsDefault == isDefault) { 551 if (canDispathEventLocked(service, event, mHandledFeedbackTypes)) { 552 mHandledFeedbackTypes |= service.mFeedbackType; 553 notifyAccessibilityServiceDelayedLocked(service, event); 554 } 555 } 556 } 557 } catch (IndexOutOfBoundsException oobe) { 558 // An out of bounds exception can happen if services are going away 559 // as the for loop is running. If that happens, just bail because 560 // there are no more services to notify. 561 return; 562 } 563 } 564 565 /** 566 * Performs an {@link AccessibilityService} delayed notification. The delay is configurable 567 * and denotes the period after the last event before notifying the service. 568 * 569 * @param service The service. 570 * @param event The event. 571 */ 572 private void notifyAccessibilityServiceDelayedLocked(Service service, 573 AccessibilityEvent event) { 574 synchronized (mLock) { 575 final int eventType = event.getEventType(); 576 // Make a copy since during dispatch it is possible the event to 577 // be modified to remove its source if the receiving service does 578 // not have permission to access the window content. 579 AccessibilityEvent newEvent = AccessibilityEvent.obtain(event); 580 AccessibilityEvent oldEvent = service.mPendingEvents.get(eventType); 581 service.mPendingEvents.put(eventType, newEvent); 582 583 final int what = eventType | (service.mId << 16); 584 if (oldEvent != null) { 585 mHandler.removeMessages(what); 586 oldEvent.recycle(); 587 } 588 589 Message message = mHandler.obtainMessage(what, service); 590 message.arg1 = eventType; 591 mHandler.sendMessageDelayed(message, service.mNotificationTimeout); 592 } 593 } 594 595 /** 596 * Notifies a service for a scheduled event given the event type. 597 * 598 * @param service The service. 599 * @param eventType The type of the event to dispatch. 600 */ 601 private void notifyEventListenerLocked(Service service, int eventType) { 602 IEventListener listener = service.mServiceInterface; 603 604 // If the service died/was disabled while the message for dispatching 605 // the accessibility event was propagating the listener may be null. 606 if (listener == null) { 607 return; 608 } 609 610 AccessibilityEvent event = service.mPendingEvents.get(eventType); 611 612 // Check for null here because there is a concurrent scenario in which this 613 // happens: 1) A binder thread calls notifyAccessibilityServiceDelayedLocked 614 // which posts a message for dispatching an event. 2) The message is pulled 615 // from the queue by the handler on the service thread and the latter is 616 // just about to acquire the lock and call this method. 3) Now another binder 617 // thread acquires the lock calling notifyAccessibilityServiceDelayedLocked 618 // so the service thread waits for the lock; 4) The binder thread replaces 619 // the event with a more recent one (assume the same event type) and posts a 620 // dispatch request releasing the lock. 5) Now the main thread is unblocked and 621 // dispatches the event which is removed from the pending ones. 6) And ... now 622 // the service thread handles the last message posted by the last binder call 623 // but the event is already dispatched and hence looking it up in the pending 624 // ones yields null. This check is much simpler that keeping count for each 625 // event type of each service to catch such a scenario since only one message 626 // is processed at a time. 627 if (event == null) { 628 return; 629 } 630 631 service.mPendingEvents.remove(eventType); 632 try { 633 if (mSecurityPolicy.canRetrieveWindowContent(service)) { 634 event.setConnectionId(service.mId); 635 } else { 636 event.setSource(null); 637 } 638 event.setSealed(true); 639 listener.onAccessibilityEvent(event); 640 event.recycle(); 641 if (DEBUG) { 642 Slog.i(LOG_TAG, "Event " + event + " sent to " + listener); 643 } 644 } catch (RemoteException re) { 645 Slog.e(LOG_TAG, "Error during sending " + event + " to " + service.mService, re); 646 } 647 } 648 649 /** 650 * Adds a service. 651 * 652 * @param service The service to add. 653 */ 654 private void tryAddServiceLocked(Service service) { 655 try { 656 if (mServices.contains(service) || !service.isConfigured()) { 657 return; 658 } 659 service.linkToOwnDeath(); 660 mServices.add(service); 661 mComponentNameToServiceMap.put(service.mComponentName, service); 662 updateInputFilterLocked(); 663 } catch (RemoteException e) { 664 /* do nothing */ 665 } 666 } 667 668 /** 669 * Removes a service. 670 * 671 * @param service The service. 672 * @return True if the service was removed, false otherwise. 673 */ 674 private boolean tryRemoveServiceLocked(Service service) { 675 final boolean removed = mServices.remove(service); 676 if (!removed) { 677 return false; 678 } 679 mComponentNameToServiceMap.remove(service.mComponentName); 680 mHandler.removeMessages(service.mId); 681 service.unlinkToOwnDeath(); 682 service.dispose(); 683 updateInputFilterLocked(); 684 return removed; 685 } 686 687 /** 688 * Determines if given event can be dispatched to a service based on the package of the 689 * event source and already notified services for that event type. Specifically, a 690 * service is notified if it is interested in events from the package and no other service 691 * providing the same feedback type has been notified. Exception are services the 692 * provide generic feedback (feedback type left as a safety net for unforeseen feedback 693 * types) which are always notified. 694 * 695 * @param service The potential receiver. 696 * @param event The event. 697 * @param handledFeedbackTypes The feedback types for which services have been notified. 698 * @return True if the listener should be notified, false otherwise. 699 */ 700 private boolean canDispathEventLocked(Service service, AccessibilityEvent event, 701 int handledFeedbackTypes) { 702 703 if (!service.isConfigured()) { 704 return false; 705 } 706 707 int eventType = event.getEventType(); 708 if ((service.mEventTypes & eventType) != eventType) { 709 return false; 710 } 711 712 Set<String> packageNames = service.mPackageNames; 713 CharSequence packageName = event.getPackageName(); 714 715 if (packageNames.isEmpty() || packageNames.contains(packageName)) { 716 int feedbackType = service.mFeedbackType; 717 if ((handledFeedbackTypes & feedbackType) != feedbackType 718 || feedbackType == AccessibilityServiceInfo.FEEDBACK_GENERIC) { 719 return true; 720 } 721 } 722 723 return false; 724 } 725 726 /** 727 * Manages services by starting enabled ones and stopping disabled ones. 728 */ 729 private void manageServicesLocked() { 730 unbindAutomationService(); 731 populateEnabledServicesLocked(mEnabledServices); 732 final int enabledInstalledServicesCount = updateServicesStateLocked(mInstalledServices, 733 mEnabledServices); 734 // No enabled installed services => disable accessibility to avoid 735 // sending accessibility events with no recipient across processes. 736 if (mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) { 737 Settings.Secure.putInt(mContext.getContentResolver(), 738 Settings.Secure.ACCESSIBILITY_ENABLED, 0); 739 } 740 } 741 742 /** 743 * Unbinds all bound services. 744 */ 745 private void unbindAllServicesLocked() { 746 List<Service> services = mServices; 747 748 for (int i = 0, count = services.size(); i < count; i++) { 749 Service service = services.get(i); 750 if (service.unbind()) { 751 i--; 752 count--; 753 } 754 } 755 } 756 757 /** 758 * Unbinds the automation service if such is running. 759 */ 760 private void unbindAutomationService() { 761 List<Service> runningServices = mServices; 762 int runningServiceCount = mServices.size(); 763 for (int i = 0; i < runningServiceCount; i++) { 764 Service service = runningServices.get(i); 765 if (service.mIsAutomation) { 766 service.unbind(); 767 return; 768 } 769 } 770 } 771 772 /** 773 * Populates a list with the {@link ComponentName}s of all enabled 774 * {@link AccessibilityService}s. 775 * 776 * @param enabledServices The list. 777 */ 778 private void populateEnabledServicesLocked(Set<ComponentName> enabledServices) { 779 enabledServices.clear(); 780 781 String servicesValue = Settings.Secure.getString(mContext.getContentResolver(), 782 Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 783 784 if (servicesValue != null) { 785 TextUtils.SimpleStringSplitter splitter = mStringColonSplitter; 786 splitter.setString(servicesValue); 787 while (splitter.hasNext()) { 788 String str = splitter.next(); 789 if (str == null || str.length() <= 0) { 790 continue; 791 } 792 ComponentName enabledService = ComponentName.unflattenFromString(str); 793 if (enabledService != null) { 794 enabledServices.add(enabledService); 795 } 796 } 797 } 798 } 799 800 /** 801 * Updates the state of each service by starting (or keeping running) enabled ones and 802 * stopping the rest. 803 * 804 * @param installedServices All installed {@link AccessibilityService}s. 805 * @param enabledServices The {@link ComponentName}s of the enabled services. 806 * @return The number of enabled installed services. 807 */ 808 private int updateServicesStateLocked(List<AccessibilityServiceInfo> installedServices, 809 Set<ComponentName> enabledServices) { 810 811 Map<ComponentName, Service> componentNameToServiceMap = mComponentNameToServiceMap; 812 boolean isEnabled = mIsAccessibilityEnabled; 813 814 int enabledInstalledServices = 0; 815 for (int i = 0, count = installedServices.size(); i < count; i++) { 816 AccessibilityServiceInfo installedService = installedServices.get(i); 817 ComponentName componentName = ComponentName.unflattenFromString( 818 installedService.getId()); 819 Service service = componentNameToServiceMap.get(componentName); 820 821 if (isEnabled) { 822 if (enabledServices.contains(componentName)) { 823 if (service == null) { 824 service = new Service(componentName, installedService, false); 825 } 826 service.bind(); 827 enabledInstalledServices++; 828 } else { 829 if (service != null) { 830 service.unbind(); 831 } 832 } 833 } else { 834 if (service != null) { 835 service.unbind(); 836 } 837 } 838 } 839 840 return enabledInstalledServices; 841 } 842 843 /** 844 * Sends the state to the clients. 845 */ 846 private void sendStateToClientsLocked() { 847 final int state = getState(); 848 for (int i = 0, count = mClients.size(); i < count; i++) { 849 try { 850 mClients.get(i).setState(state); 851 } catch (RemoteException re) { 852 mClients.remove(i); 853 count--; 854 i--; 855 } 856 } 857 } 858 859 /** 860 * Gets the current state as a set of flags. 861 * 862 * @return The state. 863 */ 864 private int getState() { 865 int state = 0; 866 if (mIsAccessibilityEnabled) { 867 state |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED; 868 } 869 // Touch exploration relies on enabled accessibility. 870 if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) { 871 state |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED; 872 } 873 return state; 874 } 875 876 /** 877 * Updates the touch exploration state. 878 */ 879 private void updateInputFilterLocked() { 880 if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) { 881 if (!mHasInputFilter) { 882 mHasInputFilter = true; 883 if (mInputFilter == null) { 884 mInputFilter = new AccessibilityInputFilter(mContext); 885 } 886 mWindowManagerService.setInputFilter(mInputFilter); 887 } 888 return; 889 } 890 if (mHasInputFilter) { 891 mHasInputFilter = false; 892 mWindowManagerService.setInputFilter(null); 893 } 894 } 895 896 /** 897 * Updated the state based on the accessibility enabled setting. 898 */ 899 private void handleAccessibilityEnabledSettingChangedLocked() { 900 mIsAccessibilityEnabled = Settings.Secure.getInt( 901 mContext.getContentResolver(), 902 Settings.Secure.ACCESSIBILITY_ENABLED, 0) == 1; 903 if (mIsAccessibilityEnabled) { 904 manageServicesLocked(); 905 } else { 906 unbindAllServicesLocked(); 907 } 908 updateInputFilterLocked(); 909 sendStateToClientsLocked(); 910 } 911 912 private class AccessibilityConnectionWrapper implements DeathRecipient { 913 private final int mWindowId; 914 private final IAccessibilityInteractionConnection mConnection; 915 916 public AccessibilityConnectionWrapper(int windowId, 917 IAccessibilityInteractionConnection connection) { 918 mWindowId = windowId; 919 mConnection = connection; 920 } 921 922 public void linkToDeath() throws RemoteException { 923 mConnection.asBinder().linkToDeath(this, 0); 924 } 925 926 public void unlinkToDeath() { 927 mConnection.asBinder().unlinkToDeath(this, 0); 928 } 929 930 @Override 931 public void binderDied() { 932 unlinkToDeath(); 933 synchronized (mLock) { 934 removeAccessibilityInteractionConnectionLocked(mWindowId); 935 } 936 } 937 } 938 939 /** 940 * This class represents an accessibility service. It stores all per service 941 * data required for the service management, provides API for starting/stopping the 942 * service and is responsible for adding/removing the service in the data structures 943 * for service management. The class also exposes configuration interface that is 944 * passed to the service it represents as soon it is bound. It also serves as the 945 * connection for the service. 946 */ 947 class Service extends IAccessibilityServiceConnection.Stub 948 implements ServiceConnection, DeathRecipient { 949 int mId = 0; 950 951 AccessibilityServiceInfo mAccessibilityServiceInfo; 952 953 IBinder mService; 954 955 IEventListener mServiceInterface; 956 957 int mEventTypes; 958 959 int mFeedbackType; 960 961 Set<String> mPackageNames = new HashSet<String>(); 962 963 boolean mIsDefault; 964 965 long mNotificationTimeout; 966 967 ComponentName mComponentName; 968 969 Intent mIntent; 970 971 boolean mCanRetrieveScreenContent; 972 973 boolean mIsAutomation; 974 975 final Rect mTempBounds = new Rect(); 976 977 // the events pending events to be dispatched to this service 978 final SparseArray<AccessibilityEvent> mPendingEvents = 979 new SparseArray<AccessibilityEvent>(); 980 981 public Service(ComponentName componentName, 982 AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) { 983 mId = sIdCounter++; 984 mComponentName = componentName; 985 mAccessibilityServiceInfo = accessibilityServiceInfo; 986 mIsAutomation = isAutomation; 987 if (!isAutomation) { 988 mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent(); 989 mIntent = new Intent().setComponent(mComponentName); 990 mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL, 991 com.android.internal.R.string.accessibility_binding_label); 992 mIntent.putExtra(Intent.EXTRA_CLIENT_INTENT, PendingIntent.getActivity( 993 mContext, 0, new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS), 0)); 994 } else { 995 mCanRetrieveScreenContent = true; 996 } 997 setDynamicallyConfigurableProperties(accessibilityServiceInfo); 998 } 999 1000 public void setDynamicallyConfigurableProperties(AccessibilityServiceInfo info) { 1001 mEventTypes = info.eventTypes; 1002 mFeedbackType = info.feedbackType; 1003 String[] packageNames = info.packageNames; 1004 if (packageNames != null) { 1005 mPackageNames.addAll(Arrays.asList(packageNames)); 1006 } 1007 mNotificationTimeout = info.notificationTimeout; 1008 mIsDefault = (info.flags & AccessibilityServiceInfo.DEFAULT) != 0; 1009 1010 synchronized (mLock) { 1011 tryAddServiceLocked(this); 1012 } 1013 } 1014 1015 /** 1016 * Binds to the accessibility service. 1017 * 1018 * @return True if binding is successful. 1019 */ 1020 public boolean bind() { 1021 if (!mIsAutomation && mService == null) { 1022 return mContext.bindService(mIntent, this, Context.BIND_AUTO_CREATE); 1023 } 1024 return false; 1025 } 1026 1027 /** 1028 * Unbinds form the accessibility service and removes it from the data 1029 * structures for service management. 1030 * 1031 * @return True if unbinding is successful. 1032 */ 1033 public boolean unbind() { 1034 if (mService != null) { 1035 synchronized (mLock) { 1036 tryRemoveServiceLocked(this); 1037 } 1038 if (!mIsAutomation) { 1039 mContext.unbindService(this); 1040 } 1041 return true; 1042 } 1043 return false; 1044 } 1045 1046 /** 1047 * Returns if the service is configured i.e. at least event types of interest 1048 * and feedback type must be set. 1049 * 1050 * @return True if the service is configured, false otherwise. 1051 */ 1052 public boolean isConfigured() { 1053 return (mEventTypes != 0 && mFeedbackType != 0 && mService != null); 1054 } 1055 1056 public void setServiceInfo(AccessibilityServiceInfo info) { 1057 mCaller.obtainMessageOO(DO_SET_SERVICE_INFO, info, this).sendToTarget(); 1058 } 1059 1060 public void onServiceConnected(ComponentName componentName, IBinder service) { 1061 mService = service; 1062 mServiceInterface = IEventListener.Stub.asInterface(service); 1063 try { 1064 mServiceInterface.setConnection(this, mId); 1065 synchronized (mLock) { 1066 tryAddServiceLocked(this); 1067 } 1068 } catch (RemoteException re) { 1069 Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re); 1070 } 1071 } 1072 1073 public float findAccessibilityNodeInfoByViewIdInActiveWindow(int viewId, 1074 int interactionId, IAccessibilityInteractionConnectionCallback callback, 1075 long interrogatingTid) 1076 throws RemoteException { 1077 IAccessibilityInteractionConnection connection = null; 1078 synchronized (mLock) { 1079 mSecurityPolicy.enforceCanRetrieveWindowContent(this); 1080 final boolean permissionGranted = mSecurityPolicy.canRetrieveWindowContent(this); 1081 if (!permissionGranted) { 1082 return 0; 1083 } else { 1084 connection = getConnectionToRetrievalAllowingWindowLocked(); 1085 if (connection == null) { 1086 if (DEBUG) { 1087 Slog.e(LOG_TAG, "No interaction connection to a retrieve " 1088 + "allowing window."); 1089 } 1090 return 0; 1091 } 1092 } 1093 } 1094 final int interrogatingPid = Binder.getCallingPid(); 1095 final long identityToken = Binder.clearCallingIdentity(); 1096 try { 1097 connection.findAccessibilityNodeInfoByViewId(viewId, interactionId, callback, 1098 interrogatingPid, interrogatingTid); 1099 } catch (RemoteException re) { 1100 if (DEBUG) { 1101 Slog.e(LOG_TAG, "Error finding node."); 1102 } 1103 } finally { 1104 Binder.restoreCallingIdentity(identityToken); 1105 } 1106 return getCompatibilityScale(mSecurityPolicy.getRetrievalAllowingWindowLocked()); 1107 } 1108 1109 public float findAccessibilityNodeInfosByViewTextInActiveWindow( 1110 String text, int interactionId, 1111 IAccessibilityInteractionConnectionCallback callback, long threadId) 1112 throws RemoteException { 1113 return findAccessibilityNodeInfosByViewText(text, 1114 mSecurityPolicy.mRetrievalAlowingWindowId, View.NO_ID, interactionId, callback, 1115 threadId); 1116 } 1117 1118 public float findAccessibilityNodeInfosByViewText(String text, 1119 int accessibilityWindowId, int accessibilityViewId, int interactionId, 1120 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 1121 throws RemoteException { 1122 IAccessibilityInteractionConnection connection = null; 1123 synchronized (mLock) { 1124 mSecurityPolicy.enforceCanRetrieveWindowContent(this); 1125 final boolean permissionGranted = 1126 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId); 1127 if (!permissionGranted) { 1128 return 0; 1129 } else { 1130 connection = getConnectionToRetrievalAllowingWindowLocked(); 1131 if (connection == null) { 1132 if (DEBUG) { 1133 Slog.e(LOG_TAG, "No interaction connection to focused window."); 1134 } 1135 return 0; 1136 } 1137 } 1138 } 1139 final int interrogatingPid = Binder.getCallingPid(); 1140 final long identityToken = Binder.clearCallingIdentity(); 1141 try { 1142 connection.findAccessibilityNodeInfosByViewText(text, accessibilityViewId, 1143 interactionId, callback, interrogatingPid, interrogatingTid); 1144 } catch (RemoteException re) { 1145 if (DEBUG) { 1146 Slog.e(LOG_TAG, "Error finding node."); 1147 } 1148 } finally { 1149 Binder.restoreCallingIdentity(identityToken); 1150 } 1151 return getCompatibilityScale(accessibilityWindowId); 1152 } 1153 1154 public float findAccessibilityNodeInfoByAccessibilityId(int accessibilityWindowId, 1155 int accessibilityViewId, int interactionId, 1156 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) 1157 throws RemoteException { 1158 IAccessibilityInteractionConnection connection = null; 1159 synchronized (mLock) { 1160 mSecurityPolicy.enforceCanRetrieveWindowContent(this); 1161 final boolean permissionGranted = 1162 mSecurityPolicy.canGetAccessibilityNodeInfoLocked(this, accessibilityWindowId); 1163 if (!permissionGranted) { 1164 return 0; 1165 } else { 1166 AccessibilityConnectionWrapper wrapper = 1167 mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId); 1168 if (wrapper == null) { 1169 if (DEBUG) { 1170 Slog.e(LOG_TAG, "No interaction connection to window: " 1171 + accessibilityWindowId); 1172 } 1173 return 0; 1174 } 1175 connection = wrapper.mConnection; 1176 } 1177 } 1178 final int interrogatingPid = Binder.getCallingPid(); 1179 final long identityToken = Binder.clearCallingIdentity(); 1180 try { 1181 connection.findAccessibilityNodeInfoByAccessibilityId(accessibilityViewId, 1182 interactionId, callback, interrogatingPid, interrogatingTid); 1183 } catch (RemoteException re) { 1184 if (DEBUG) { 1185 Slog.e(LOG_TAG, "Error requesting node with accessibilityViewId: " 1186 + accessibilityViewId); 1187 } 1188 } finally { 1189 Binder.restoreCallingIdentity(identityToken); 1190 } 1191 return getCompatibilityScale(accessibilityWindowId); 1192 } 1193 1194 public boolean performAccessibilityAction(int accessibilityWindowId, 1195 int accessibilityViewId, int action, int interactionId, 1196 IAccessibilityInteractionConnectionCallback callback, long interrogatingTid) { 1197 IAccessibilityInteractionConnection connection = null; 1198 synchronized (mLock) { 1199 final boolean permissionGranted = mSecurityPolicy.canPerformActionLocked(this, 1200 accessibilityWindowId, action); 1201 if (!permissionGranted) { 1202 return false; 1203 } else { 1204 AccessibilityConnectionWrapper wrapper = 1205 mWindowIdToInteractionConnectionWrapperMap.get(accessibilityWindowId); 1206 if (wrapper == null) { 1207 if (DEBUG) { 1208 Slog.e(LOG_TAG, "No interaction connection to window: " 1209 + accessibilityWindowId); 1210 } 1211 return false; 1212 } 1213 connection = wrapper.mConnection; 1214 } 1215 } 1216 final int interrogatingPid = Binder.getCallingPid(); 1217 final long identityToken = Binder.clearCallingIdentity(); 1218 try { 1219 connection.performAccessibilityAction(accessibilityViewId, action, interactionId, 1220 callback, interrogatingPid, interrogatingTid); 1221 } catch (RemoteException re) { 1222 if (DEBUG) { 1223 Slog.e(LOG_TAG, "Error requesting node with accessibilityViewId: " 1224 + accessibilityViewId); 1225 } 1226 } finally { 1227 Binder.restoreCallingIdentity(identityToken); 1228 } 1229 return true; 1230 } 1231 1232 public void onServiceDisconnected(ComponentName componentName) { 1233 /* do nothing - #binderDied takes care */ 1234 } 1235 1236 public void linkToOwnDeath() throws RemoteException { 1237 mService.linkToDeath(this, 0); 1238 } 1239 1240 public void unlinkToOwnDeath() { 1241 mService.unlinkToDeath(this, 0); 1242 } 1243 1244 public void dispose() { 1245 try { 1246 // Clear the proxy in the other process so this 1247 // IAccessibilityServiceConnection can be garbage collected. 1248 mServiceInterface.setConnection(null, mId); 1249 } catch (RemoteException re) { 1250 /* ignore */ 1251 } 1252 mService = null; 1253 mServiceInterface = null; 1254 } 1255 1256 public void binderDied() { 1257 synchronized (mLock) { 1258 unlinkToOwnDeath(); 1259 tryRemoveServiceLocked(this); 1260 // We no longer have an automation service, so restore 1261 // the state based on values in the settings database. 1262 if (mIsAutomation) { 1263 handleAccessibilityEnabledSettingChangedLocked(); 1264 } 1265 } 1266 } 1267 1268 private IAccessibilityInteractionConnection getConnectionToRetrievalAllowingWindowLocked() { 1269 final int windowId = mSecurityPolicy.getRetrievalAllowingWindowLocked(); 1270 if (DEBUG) { 1271 Slog.i(LOG_TAG, "Trying to get interaction connection to windowId: " + windowId); 1272 } 1273 AccessibilityConnectionWrapper wrapper = 1274 mWindowIdToInteractionConnectionWrapperMap.get(windowId); 1275 return (wrapper != null) ? wrapper.mConnection : null; 1276 } 1277 1278 private float getCompatibilityScale(int windowId) { 1279 IBinder windowToken = mWindowIdToWindowTokenMap.get(windowId); 1280 return mWindowManagerService.getWindowCompatibilityScale(windowToken); 1281 } 1282 } 1283 1284 final class SecurityPolicy { 1285 private static final int VALID_ACTIONS = AccessibilityNodeInfo.ACTION_FOCUS 1286 | AccessibilityNodeInfo.ACTION_CLEAR_FOCUS | AccessibilityNodeInfo.ACTION_SELECT 1287 | AccessibilityNodeInfo.ACTION_CLEAR_SELECTION; 1288 1289 private static final int RETRIEVAL_ALLOWING_EVENT_TYPES = 1290 AccessibilityEvent.TYPE_VIEW_CLICKED | AccessibilityEvent.TYPE_VIEW_FOCUSED 1291 | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT 1292 | AccessibilityEvent.TYPE_VIEW_LONG_CLICKED | AccessibilityEvent.TYPE_VIEW_TEXT_CHANGED 1293 | AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_SELECTED 1294 | AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 1295 | AccessibilityEvent.TYPE_VIEW_TEXT_SELECTION_CHANGED 1296 | AccessibilityEvent.TYPE_VIEW_SCROLLED; 1297 1298 private static final int RETRIEVAL_ALLOWING_WINDOW_CHANGE_EVENT_TYPES = 1299 AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED | AccessibilityEvent.TYPE_VIEW_HOVER_ENTER 1300 | AccessibilityEvent.TYPE_VIEW_HOVER_EXIT; 1301 1302 private int mRetrievalAlowingWindowId; 1303 1304 private boolean canDispatchAccessibilityEvent(AccessibilityEvent event) { 1305 // Send window changed event only for the retrieval allowing window. 1306 return (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED 1307 || event.getWindowId() == mRetrievalAlowingWindowId); 1308 } 1309 1310 public void updateRetrievalAllowingWindowAndEventSourceLocked(AccessibilityEvent event) { 1311 final int windowId = event.getWindowId(); 1312 final int eventType = event.getEventType(); 1313 if ((eventType & RETRIEVAL_ALLOWING_WINDOW_CHANGE_EVENT_TYPES) != 0) { 1314 mRetrievalAlowingWindowId = windowId; 1315 } 1316 if ((eventType & RETRIEVAL_ALLOWING_EVENT_TYPES) == 0) { 1317 event.setSource(null); 1318 } 1319 } 1320 1321 public int getRetrievalAllowingWindowLocked() { 1322 return mRetrievalAlowingWindowId; 1323 } 1324 1325 public boolean canGetAccessibilityNodeInfoLocked(Service service, int windowId) { 1326 return canRetrieveWindowContent(service) && isRetrievalAllowingWindow(windowId); 1327 } 1328 1329 public boolean canPerformActionLocked(Service service, int windowId, int action) { 1330 return canRetrieveWindowContent(service) 1331 && isRetrievalAllowingWindow(windowId) 1332 && isActionPermitted(action); 1333 } 1334 1335 public boolean canRetrieveWindowContent(Service service) { 1336 return service.mCanRetrieveScreenContent; 1337 } 1338 1339 public void enforceCanRetrieveWindowContent(Service service) throws RemoteException { 1340 // This happens due to incorrect registration so make it apparent. 1341 if (!canRetrieveWindowContent(service)) { 1342 Slog.e(LOG_TAG, "Accessibility serivce " + service.mComponentName + " does not " + 1343 "declare android:canRetrieveWindowContent."); 1344 throw new RemoteException(); 1345 } 1346 } 1347 1348 private boolean isRetrievalAllowingWindow(int windowId) { 1349 return (mRetrievalAlowingWindowId == windowId); 1350 } 1351 1352 private boolean isActionPermitted(int action) { 1353 return (VALID_ACTIONS & action) != 0; 1354 } 1355 1356 private void enforceCallingPermission(String permission, String function) { 1357 if (OWN_PROCESS_ID == Binder.getCallingPid()) { 1358 return; 1359 } 1360 final int permissionStatus = mContext.checkCallingPermission(permission); 1361 if (permissionStatus != PackageManager.PERMISSION_GRANTED) { 1362 throw new SecurityException("You do not have " + permission 1363 + " required to call " + function); 1364 } 1365 } 1366 } 1367} 1368