Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ba966d43 authored by Valentin Iftime's avatar Valentin Iftime
Browse files

Fix Toast leak in AccessibilityManager

 AccessibilityManager registers a client object in the constructor.
 So only create a AccessibilityManager when trying to send an accessibility event,
  as there may be multiple ToastPresenters initialized without being used: from the client app and SystemUi.

Test: atest WindowUntrustedTouchTest
 atest ToastWindowTest
 atest ToastPresenterTest
 atest ToastUITest

Bug: 298593662
Change-Id: Ie8a4440338d25d521eb036dc4531c820d5a35267
parent b06a5995
Loading
Loading
Loading
Loading
+15 −12
Original line number Diff line number Diff line
@@ -89,9 +89,10 @@ public class ToastPresenter {
        return view;
    }

    private final WeakReference<Context> mContext;
    private final Resources mResources;
    private final WeakReference<WindowManager> mWindowManager;
    private final WeakReference<AccessibilityManager> mAccessibilityManager;
    private final IAccessibilityManager mAccessibilityManagerService;
    private final INotificationManager mNotificationManager;
    private final String mPackageName;
    private final String mContextPackageName;
@@ -101,21 +102,14 @@ public class ToastPresenter {

    public ToastPresenter(Context context, IAccessibilityManager accessibilityManager,
            INotificationManager notificationManager, String packageName) {
        mContext = new WeakReference<>(context);
        mResources = context.getResources();
        mWindowManager = new WeakReference<>(context.getSystemService(WindowManager.class));
        mNotificationManager = notificationManager;
        mPackageName = packageName;
        mContextPackageName = context.getPackageName();
        mParams = createLayoutParams();

        // We obtain AccessibilityManager manually via its constructor instead of using method
        // AccessibilityManager.getInstance() for 2 reasons:
        //   1. We want to be able to inject IAccessibilityManager in tests to verify behavior.
        //   2. getInstance() caches the instance for the process even if we pass a different
        //      context to it. This is problematic for multi-user because callers can pass a context
        //      created via Context.createContextAsUser().
        mAccessibilityManager = new WeakReference<>(
                new AccessibilityManager(context, accessibilityManager, context.getUserId()));
        mAccessibilityManagerService = accessibilityManager;
    }

    public String getPackageName() {
@@ -306,11 +300,20 @@ public class ToastPresenter {
     * enabled.
     */
    public void trySendAccessibilityEvent(View view, String packageName) {
        final AccessibilityManager accessibilityManager = mAccessibilityManager.get();
        if (accessibilityManager == null) {
        final Context context = mContext.get();
        if (context == null) {
            return;
        }

        // We obtain AccessibilityManager manually via its constructor instead of using method
        // AccessibilityManager.getInstance() for 2 reasons:
        //   1. We want to be able to inject IAccessibilityManager in tests to verify behavior.
        //   2. getInstance() caches the instance for the process even if we pass a different
        //      context to it. This is problematic for multi-user because callers can pass a context
        //      created via Context.createContextAsUser().
        final AccessibilityManager accessibilityManager = new AccessibilityManager(context,
                    mAccessibilityManagerService, context.getUserId());

        if (!accessibilityManager.isEnabled()) {
            accessibilityManager.removeClient();
            return;