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

Commit 25da3dcd authored by Cliff Wu's avatar Cliff Wu
Browse files

Fix java.lang.ArrayIndexOutOfBoundsException at ArraySet in...

Fix java.lang.ArrayIndexOutOfBoundsException at ArraySet in GenericWindowPolicyController.onRunningAppsChanged()

- Before iterating over mRunningAppsChangedListener, we need to confirm
  whether there is a listener in mRunningAppsChangedListener to avoid
  ArrayIndexOutOfBoundsException.
- Use mGenericWindowPolicyControllerLock to protect
  mRunningAppsChangedListener access.

Bug: 248192490
Test: Manual
Change-Id: Iedd031f50659f027576086788392110a3432858a
parent 4489239d
Loading
Loading
Loading
Loading
+26 −8
Original line number Original line Diff line number Diff line
@@ -44,6 +44,7 @@ import android.view.Display;
import android.window.DisplayWindowPolicyController;
import android.window.DisplayWindowPolicyController;


import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.BlockedAppStreamingActivity;
import com.android.internal.app.BlockedAppStreamingActivity;


import java.util.List;
import java.util.List;
@@ -112,7 +113,9 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
    final ArraySet<Integer> mRunningUids = new ArraySet<>();
    final ArraySet<Integer> mRunningUids = new ArraySet<>();
    @Nullable private final ActivityListener mActivityListener;
    @Nullable private final ActivityListener mActivityListener;
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final Handler mHandler = new Handler(Looper.getMainLooper());
    private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListener =
    @NonNull
    @GuardedBy("mGenericWindowPolicyControllerLock")
    private final ArraySet<RunningAppsChangedListener> mRunningAppsChangedListeners =
            new ArraySet<>();
            new ArraySet<>();
    @Nullable
    @Nullable
    private final @AssociationRequest.DeviceProfile String mDeviceProfile;
    private final @AssociationRequest.DeviceProfile String mDeviceProfile;
@@ -178,12 +181,16 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController


    /** Register a listener for running applications changes. */
    /** Register a listener for running applications changes. */
    public void registerRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
    public void registerRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
        mRunningAppsChangedListener.add(listener);
        synchronized (mGenericWindowPolicyControllerLock) {
            mRunningAppsChangedListeners.add(listener);
        }
    }
    }


    /** Unregister a listener for running applications changes. */
    /** Unregister a listener for running applications changes. */
    public void unregisterRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
    public void unregisterRunningAppsChangedListener(@NonNull RunningAppsChangedListener listener) {
        mRunningAppsChangedListener.remove(listener);
        synchronized (mGenericWindowPolicyControllerLock) {
            mRunningAppsChangedListeners.remove(listener);
        }
    }
    }


    @Override
    @Override
@@ -283,13 +290,17 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
                // Post callback on the main thread so it doesn't block activity launching
                // Post callback on the main thread so it doesn't block activity launching
                mHandler.post(() -> mActivityListener.onDisplayEmpty(mDisplayId));
                mHandler.post(() -> mActivityListener.onDisplayEmpty(mDisplayId));
            }
            }
        }
            if (!mRunningAppsChangedListeners.isEmpty()) {
                final ArraySet<RunningAppsChangedListener> listeners =
                        new ArraySet<>(mRunningAppsChangedListeners);
                mHandler.post(() -> {
                mHandler.post(() -> {
            for (RunningAppsChangedListener listener : mRunningAppsChangedListener) {
                    for (RunningAppsChangedListener listener : listeners) {
                        listener.onRunningAppsChanged(runningUids);
                        listener.onRunningAppsChanged(runningUids);
                    }
                    }
                });
                });
            }
            }
        }
    }


    @Override
    @Override
    public boolean canShowTasksInRecents() {
    public boolean canShowTasksInRecents() {
@@ -354,4 +365,11 @@ public class GenericWindowPolicyController extends DisplayWindowPolicyController
        }
        }
        return true;
        return true;
    }
    }

    @VisibleForTesting
    int getRunningAppsChangedListenersSizeForTesting() {
        synchronized (mGenericWindowPolicyControllerLock) {
            return mRunningAppsChangedListeners.size();
        }
    }
}
}
+30 −0
Original line number Original line Diff line number Diff line
@@ -891,4 +891,34 @@ public class VirtualDeviceManagerServiceTest {
        verify(mContext).startActivityAsUser(argThat(intent ->
        verify(mContext).startActivityAsUser(argThat(intent ->
                intent.filterEquals(blockedAppIntent)), any(), any());
                intent.filterEquals(blockedAppIntent)), any(), any());
    }
    }

    @Test
    public void registerRunningAppsChangedListener_onRunningAppsChanged_listenersNotified() {
        ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
        mDeviceImpl.onVirtualDisplayCreatedLocked(
                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
        GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                DISPLAY_ID);

        gwpc.onRunningAppsChanged(uids);
        mDeviceImpl.onRunningAppsChanged(uids);

        assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(1);
        verify(mRunningAppsChangedCallback).accept(new ArraySet<>(Arrays.asList(UID_1, UID_2)));
    }

    @Test
    public void noRunningAppsChangedListener_onRunningAppsChanged_doesNotThrowException() {
        ArraySet<Integer> uids = new ArraySet<>(Arrays.asList(UID_1, UID_2));
        mDeviceImpl.onVirtualDisplayCreatedLocked(
                mDeviceImpl.createWindowPolicyController(), DISPLAY_ID);
        GenericWindowPolicyController gwpc = mDeviceImpl.getWindowPolicyControllersForTesting().get(
                DISPLAY_ID);
        mDeviceImpl.onVirtualDisplayRemovedLocked(DISPLAY_ID);

        // This call should not throw any exceptions.
        gwpc.onRunningAppsChanged(uids);

        assertThat(gwpc.getRunningAppsChangedListenersSizeForTesting()).isEqualTo(0);
    }
}
}