From 4a41eca71b4ad3c1a3203373492b1affd3bb4126 Mon Sep 17 00:00:00 2001 From: Sally Date: Wed, 2 Jun 2021 21:25:52 +0000 Subject: [PATCH] Add AccessibilityManager#removeClient Whenever an app makes a Text toast, this gets routed through systemUI starting from R. Two A11yManagerClients are registered with A11yManagerService for every toast. Since clients aren't removed until the process is killed, there are a bunch of clients from systemui hanging around and potentially cause the system to crash. We add a way here to explicitly unregister a client Test: build and flash, atest android.view.accessibility.AccessibilityManagerTest Bug: 189010828 Change-Id: I3f71bac475b4539c7be5b328adeb0be35a0b5543 --- .../accessibility/AccessibilityManager.java | 19 ++++++++++ .../accessibility/IAccessibilityManager.aidl | 2 ++ .../AccessibilityManagerTest.java | 7 ++++ .../AccessibilityManagerService.java | 36 +++++++++++++++++++ .../accessibility/AccessibilityUserState.java | 10 ++++++ 5 files changed, 74 insertions(+) diff --git a/core/java/android/view/accessibility/AccessibilityManager.java b/core/java/android/view/accessibility/AccessibilityManager.java index fc9e5e2ef04e0..f9cdbd322c260 100644 --- a/core/java/android/view/accessibility/AccessibilityManager.java +++ b/core/java/android/view/accessibility/AccessibilityManager.java @@ -516,6 +516,25 @@ public final class AccessibilityManager { return mClient; } + /** + * Unregisters the IAccessibilityManagerClient from the backing service + * @hide + */ + public boolean removeClient() { + synchronized (mLock) { + IAccessibilityManager service = getServiceLocked(); + if (service == null) { + return false; + } + try { + return service.removeClient(mClient, mUserId); + } catch (RemoteException re) { + Log.e(LOG_TAG, "AccessibilityManagerService is dead", re); + } + } + return false; + } + /** * @hide */ diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl index c71ea53c414d9..078ab25e8b6c8 100644 --- a/core/java/android/view/accessibility/IAccessibilityManager.aidl +++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl @@ -42,6 +42,8 @@ interface IAccessibilityManager { long addClient(IAccessibilityManagerClient client, int userId); + boolean removeClient(IAccessibilityManagerClient client, int userId); + List getInstalledAccessibilityServiceList(int userId); @UnsupportedAppUsage(maxTargetSdk = 30, trackingBug = 170729553) diff --git a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java index 115c266aaae6d..212fdcace6ac8 100644 --- a/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java +++ b/core/tests/coretests/src/android/view/accessibility/AccessibilityManagerTest.java @@ -115,6 +115,13 @@ public class AccessibilityManagerTest { return manager; } + @Test + public void testRemoveManager() throws Exception { + AccessibilityManager manager = createManager(WITH_A11Y_ENABLED); + manager.removeClient(); + verify(mMockService).removeClient(manager.getClient(), UserHandle.USER_CURRENT); + } + @Test public void testGetAccessibilityServiceList() throws Exception { // create a list of installed accessibility services the mock service returns diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 9abe00fba98c2..7eecc453a8ce8 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -709,6 +709,34 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub } } + @Override + public boolean removeClient(IAccessibilityManagerClient callback, int userId) { + // TODO(b/190216606): Add tracing for removeClient when implementation is the same in master + + synchronized (mLock) { + final int resolvedUserId = mSecurityPolicy + .resolveCallingUserIdEnforcingPermissionsLocked(userId); + + AccessibilityUserState userState = getUserStateLocked(resolvedUserId); + if (mSecurityPolicy.isCallerInteractingAcrossUsers(userId)) { + boolean unregistered = mGlobalClients.unregister(callback); + if (DEBUG) { + Slog.i(LOG_TAG, + "Removed global client for pid:" + Binder.getCallingPid() + "state: " + + unregistered); + } + return unregistered; + } else { + boolean unregistered = userState.mUserClients.unregister(callback); + if (DEBUG) { + Slog.i(LOG_TAG, "Removed user client for pid:" + Binder.getCallingPid() + + " and userId:" + resolvedUserId + "state: " + unregistered); + } + return unregistered; + } + } + } + @Override public void sendAccessibilityEvent(AccessibilityEvent event, int userId) { if (mTraceManager.isA11yTracingEnabled()) { @@ -3271,6 +3299,14 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub pw.println(); } mA11yWindowManager.dump(fd, pw, args); + pw.println("Global client list info:{"); + mGlobalClients.dump(pw, " Client list "); + pw.println(" Registered clients:{"); + for (int i = 0; i < mGlobalClients.getRegisteredCallbackCount(); i++) { + AccessibilityManagerService.Client client = (AccessibilityManagerService.Client) + mGlobalClients.getRegisteredCallbackCookie(i); + pw.append(Arrays.toString(client.mPackageNames)); + } } } diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java index df349c863128e..0fde0de59c076 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityUserState.java @@ -51,6 +51,7 @@ import com.android.internal.accessibility.AccessibilityShortcutController; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; @@ -573,6 +574,15 @@ class AccessibilityUserState { pw.append(componentName.toShortString()); } } + pw.println("}"); + pw.println(" Client list info:{"); + mUserClients.dump(pw, " Client list "); + pw.println(" Registered clients:{"); + for (int i = 0; i < mUserClients.getRegisteredCallbackCount(); i++) { + AccessibilityManagerService.Client client = (AccessibilityManagerService.Client) + mUserClients.getRegisteredCallbackCookie(i); + pw.append(Arrays.toString(client.mPackageNames)); + } pw.println("}]"); }