From ab5975c6afadc3251ce1190f27801d822f14c9d5 Mon Sep 17 00:00:00 2001 From: sallyyuen Date: Thu, 6 Oct 2022 12:33:32 -0700 Subject: [PATCH] [EXO] Add aidl methods for registering and unregistering a proxy - Implement register/unregisterProxy minimally. These are mostly validity checks. Future CLs will expose the SystemAPI methods on A11yManager so an app can call through to these. - Introduce a ProxyManager skeleton. This will be populated and tested in future CLs. Bug: 241429275 Test: builds, atest AccessibilityManagerServiceTest Change-Id: Idebf46590b5a129381a34496de67ed18d43369ed --- .../accessibility/IAccessibilityManager.aidl | 6 +++ .../AccessibilityManagerService.java | 49 ++++++++++++++++++- .../server/accessibility/ProxyManager.java | 46 +++++++++++++++++ .../AccessibilityManagerServiceTest.java | 47 +++++++++++++++++- 4 files changed, 146 insertions(+), 2 deletions(-) create mode 100644 services/accessibility/java/com/android/server/accessibility/ProxyManager.java diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index 1e060987b69f3..36fdcce4e1f25 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -108,4 +108,10 @@ interface IAccessibilityManager { void setSystemAudioCaptioningUiEnabled(boolean isEnabled, int userId); oneway void setAccessibilityWindowAttributes(int displayId, int windowId, int userId, in AccessibilityWindowAttributes attributes); + + // Requires Manifest.permission.MANAGE_ACCESSIBILITY + boolean registerProxyForDisplay(IAccessibilityServiceClient proxy, int displayId); + + // Requires Manifest.permission.MANAGE_ACCESSIBILITY + boolean unregisterProxyForDisplay(int displayId); } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 1efbb0a3c171d..365068d22171e 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -277,6 +277,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub final SparseArray mUserStates = new SparseArray<>(); private final UiAutomationManager mUiAutomationManager = new UiAutomationManager(mLock); + private final ProxyManager mProxyManager; private final AccessibilityTraceManager mTraceManager; private final CaptioningManagerImpl mCaptioningManagerImpl; @@ -396,7 +397,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub AccessibilityWindowManager a11yWindowManager, AccessibilityDisplayListener a11yDisplayListener, MagnificationController magnificationController, - @Nullable AccessibilityInputFilter inputFilter) { + @Nullable AccessibilityInputFilter inputFilter, + ProxyManager proxyManager) { mContext = context; mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE); mWindowManagerService = LocalServices.getService(WindowManagerInternal.class); @@ -412,6 +414,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mMagnificationController = magnificationController; mMagnificationProcessor = new MagnificationProcessor(mMagnificationController); mCaptioningManagerImpl = new CaptioningManagerImpl(mContext); + mProxyManager = proxyManager; if (inputFilter != null) { mInputFilter = inputFilter; mHasInputFilter = true; @@ -445,6 +448,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub new MagnificationScaleProvider(mContext)); mMagnificationProcessor = new MagnificationProcessor(mMagnificationController); mCaptioningManagerImpl = new CaptioningManagerImpl(mContext); + mProxyManager = new ProxyManager(mLock); init(); } @@ -3601,6 +3605,34 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub mCaptioningManagerImpl.setSystemAudioCaptioningUiEnabled(isEnabled, userId); } + @Override + public boolean registerProxyForDisplay(IAccessibilityServiceClient client, int displayId) + throws RemoteException { + mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY); + if (client == null) { + return false; + } + if (displayId < 0) { + throw new IllegalArgumentException("The display id " + displayId + " is invalid."); + } + if (displayId == Display.DEFAULT_DISPLAY) { + throw new IllegalArgumentException("The default display cannot be proxy-ed."); + } + if (!isTrackedDisplay(displayId)) { + throw new IllegalArgumentException("The display " + displayId + " does not exist or is" + + " not tracked by accessibility."); + } + + mProxyManager.registerProxy(client, displayId); + return true; + } + + @Override + public boolean unregisterProxyForDisplay(int displayId) throws RemoteException { + mSecurityPolicy.enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY); + return mProxyManager.unregisterProxy(displayId); + } + @Override public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) { if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return; @@ -3830,6 +3862,21 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub return mA11yDisplayListener.getValidDisplayList(); } + + /** + * Returns {@code true} if the display id is in the list of currently valid logical displays + * being tracked by a11y. + */ + private boolean isTrackedDisplay(int displayId) { + final ArrayList displays = getValidDisplayList(); + for (Display display : displays) { + if (display.getDisplayId() == displayId) { + return true; + } + } + return false; + } + /** * A Utility class to handle display state. */ diff --git a/services/accessibility/java/com/android/server/accessibility/ProxyManager.java b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java new file mode 100644 index 0000000000000..fb0b8f3b17b17 --- /dev/null +++ b/services/accessibility/java/com/android/server/accessibility/ProxyManager.java @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.accessibility; +import android.accessibilityservice.IAccessibilityServiceClient; + +/** + * Manages proxy connections. + * + * Currently this acts similarly to UiAutomationManager as a global manager, though ideally each + * proxy connection will belong to a separate user state. + * + * TODO(241117292): Remove or cut down during simultaneous user refactoring. + */ +public class ProxyManager { + private final Object mLock; + + ProxyManager(Object lock) { + mLock = lock; + } + + /** + * TODO: Create the proxy service connection. + */ + public void registerProxy(IAccessibilityServiceClient client, int displayId) { + } + + /** + * TODO: Unregister the proxy service connection based on display id. + */ + public boolean unregisterProxy(int displayId) { + return true; + } +} diff --git a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java index 51d78e1d3a11f..0f09252b8ca12 100644 --- a/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/accessibility/AccessibilityManagerServiceTest.java @@ -132,6 +132,7 @@ public class AccessibilityManagerServiceTest { @Mock private WindowMagnificationManager mMockWindowMagnificationMgr; @Mock private MagnificationController mMockMagnificationController; @Mock private FullScreenMagnificationController mMockFullScreenMagnificationController; + @Mock private ProxyManager mProxyManager; @Rule public final TestableContext mTestableContext = new TestableContext( @@ -184,7 +185,8 @@ public class AccessibilityManagerServiceTest { mMockA11yWindowManager, mMockA11yDisplayListener, mMockMagnificationController, - mInputFilter); + mInputFilter, + mProxyManager); final AccessibilityUserState userState = new AccessibilityUserState( mA11yms.getCurrentUserIdLocked(), mTestableContext, mA11yms); @@ -276,6 +278,49 @@ public class AccessibilityManagerServiceTest { verify(mMockServiceClient).onSystemActionsChanged(); } + @SmallTest + @Test + public void testRegisterProxy() throws Exception { + mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY); + verify(mProxyManager).registerProxy(mMockServiceClient, TEST_DISPLAY); + } + + + @SmallTest + @Test + public void testRegisterProxyWithoutPermission() throws Exception { + doThrow(SecurityException.class).when(mMockSecurityPolicy) + .enforceCallingOrSelfPermission(Manifest.permission.MANAGE_ACCESSIBILITY); + try { + mA11yms.registerProxyForDisplay(mMockServiceClient, TEST_DISPLAY); + Assert.fail(); + } catch (SecurityException expected) { + } + verify(mProxyManager, never()).registerProxy(mMockServiceClient, TEST_DISPLAY); + } + + @SmallTest + @Test + public void testRegisterProxyForDefaultDisplay() throws Exception { + try { + mA11yms.registerProxyForDisplay(mMockServiceClient, Display.DEFAULT_DISPLAY); + Assert.fail(); + } catch (IllegalArgumentException expected) { + } + verify(mProxyManager, never()).registerProxy(mMockServiceClient, Display.DEFAULT_DISPLAY); + } + + @SmallTest + @Test + public void testRegisterProxyForInvalidDisplay() throws Exception { + try { + mA11yms.registerProxyForDisplay(mMockServiceClient, Display.INVALID_DISPLAY); + Assert.fail(); + } catch (IllegalArgumentException expected) { + } + verify(mProxyManager, never()).registerProxy(mMockServiceClient, Display.INVALID_DISPLAY); + } + @SmallTest @Test public void testOnMagnificationTransitionFailed_capabilitiesIsAll_fallBackToPreviousMode() {