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

Commit 003012bf authored by Fabián Kozynski's avatar Fabián Kozynski
Browse files

Move calls to RotationPolicy to bg

When callbacks are added to RotationLockControllerImpl, it queries
RotationPolicy (Settings provider) in that thread. For RotationLockTile,
this is tied to the Lifecycle state change, so it happens in the main
thread, causing binder calls in the main thread.

Instead, move them to the background, but keep the call on the
RotationLockControllerCallback in the main thread, as consumers depend
on this.

Test: manual, toggle rotation
Test: atest RotationLockControllerImplTest
Test: perfetto, see binder calls move to background
Fixes: 407698587
Flag: EXEMPT bug fix
Change-Id: I62456f7f48253be97192e9ef11ff41b52566b8d5
parent 4a8471ac
Loading
Loading
Loading
Loading
+10 −2
Original line number Original line Diff line number Diff line
@@ -52,7 +52,9 @@ import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController;
import com.android.systemui.statusbar.policy.DeviceStateRotationLockSettingController;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.RotationLockController;
import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
import com.android.systemui.statusbar.policy.RotationLockControllerImpl;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.settings.FakeSettings;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;


import org.junit.After;
import org.junit.After;
@@ -111,6 +113,7 @@ public class RotationLockTileTest extends SysuiTestCase {
    private TestableLooper mTestableLooper;
    private TestableLooper mTestableLooper;
    private RotationLockTile mLockTile;
    private RotationLockTile mLockTile;
    private TestableResources mTestableResources;
    private TestableResources mTestableResources;
    private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());


    public RotationLockTileTest(FlagsParameterization flags) {
    public RotationLockTileTest(FlagsParameterization flags) {
        super();
        super();
@@ -128,8 +131,13 @@ public class RotationLockTileTest extends SysuiTestCase {
        mTestableResources.addOverride(com.android.internal.R.bool.config_allowRotationResolver,
        mTestableResources.addOverride(com.android.internal.R.bool.config_allowRotationResolver,
                true);
                true);


        mController = new RotationLockControllerImpl(mRotationPolicyWrapper,
        mController = new RotationLockControllerImpl(
                mDeviceStateRotationLockSettingController, DEFAULT_SETTINGS);
                mRotationPolicyWrapper,
                mDeviceStateRotationLockSettingController,
                DEFAULT_SETTINGS,
                mFakeExecutor,
                mFakeExecutor
        );


        mLockTile = new RotationLockTile(
        mLockTile = new RotationLockTile(
                mHost,
                mHost,
+9 −1
Original line number Original line Diff line number Diff line
@@ -28,6 +28,8 @@ import androidx.test.filters.SmallTest;


import com.android.internal.view.RotationPolicy;
import com.android.internal.view.RotationPolicy;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;


import org.junit.Before;
import org.junit.Before;
@@ -53,6 +55,8 @@ public class RotationLockControllerImplTest extends SysuiTestCase {


    private ArgumentCaptor<RotationPolicy.RotationPolicyListener> mRotationPolicyListenerCaptor;
    private ArgumentCaptor<RotationPolicy.RotationPolicyListener> mRotationPolicyListenerCaptor;


    private FakeExecutor mFakeExecutor = new FakeExecutor(new FakeSystemClock());

    @Before
    @Before
    public void setUp() {
    public void setUp() {
        MockitoAnnotations.initMocks(/* testClass= */ this);
        MockitoAnnotations.initMocks(/* testClass= */ this);
@@ -79,6 +83,7 @@ public class RotationLockControllerImplTest extends SysuiTestCase {
    public void whenFlagOn_deviceStateRotationControllerAddedToCallbacks() {
    public void whenFlagOn_deviceStateRotationControllerAddedToCallbacks() {
        createRotationLockController();
        createRotationLockController();
        captureRotationPolicyListener().onChange();
        captureRotationPolicyListener().onChange();
        mFakeExecutor.runAllReady();


        verify(mDeviceStateRotationLockSettingController)
        verify(mDeviceStateRotationLockSettingController)
                .onRotationLockStateChanged(anyBoolean(), anyBoolean());
                .onRotationLockStateChanged(anyBoolean(), anyBoolean());
@@ -98,6 +103,9 @@ public class RotationLockControllerImplTest extends SysuiTestCase {
        new RotationLockControllerImpl(
        new RotationLockControllerImpl(
                mRotationPolicyWrapper,
                mRotationPolicyWrapper,
                Optional.of(mDeviceStateRotationLockSettingController),
                Optional.of(mDeviceStateRotationLockSettingController),
                deviceStateRotationLockDefaults);
                deviceStateRotationLockDefaults,
                mFakeExecutor,
                mFakeExecutor
        );
    }
    }
}
}
+37 −7
Original line number Original line Diff line number Diff line
@@ -23,15 +23,18 @@ import android.content.Context;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager;
import android.os.UserHandle;
import android.os.UserHandle;


import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.NonNull;


import com.android.internal.view.RotationPolicy.RotationPolicyListener;
import com.android.internal.view.RotationPolicy.RotationPolicyListener;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.dagger.SysUISingleton;
import com.android.systemui.rotationlock.DeviceStateAutoRotateModule.BoundsDeviceStateAutoRotateModule;
import com.android.systemui.dagger.qualifiers.Background;
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;
import com.android.systemui.util.wrapper.RotationPolicyWrapper;


import java.util.Optional;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.Executor;


import javax.inject.Inject;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Named;
@@ -55,13 +58,17 @@ public final class RotationLockControllerImpl implements RotationLockController
    private final Optional<DeviceStateRotationLockSettingController>
    private final Optional<DeviceStateRotationLockSettingController>
            mDeviceStateRotationLockSettingController;
            mDeviceStateRotationLockSettingController;
    private final boolean mIsPerDeviceStateRotationLockEnabled;
    private final boolean mIsPerDeviceStateRotationLockEnabled;
    private final Executor mBgExecutor;
    private final Executor mMainExecutor;


    @Inject
    @Inject
    public RotationLockControllerImpl(
    public RotationLockControllerImpl(
            RotationPolicyWrapper rotationPolicyWrapper,
            RotationPolicyWrapper rotationPolicyWrapper,
            Optional<DeviceStateRotationLockSettingController>
            Optional<DeviceStateRotationLockSettingController>
                    deviceStateRotationLockSettingController,
                    deviceStateRotationLockSettingController,
            @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults
            @Named(DEVICE_STATE_ROTATION_LOCK_DEFAULTS) String[] deviceStateRotationLockDefaults,
            @Background Executor bgExecutor,
            @Main Executor mainExecutor
    ) {
    ) {
        mRotationPolicy = rotationPolicyWrapper;
        mRotationPolicy = rotationPolicyWrapper;
        mIsPerDeviceStateRotationLockEnabled = deviceStateRotationLockDefaults.length > 0;
        mIsPerDeviceStateRotationLockEnabled = deviceStateRotationLockDefaults.length > 0;
@@ -72,6 +79,8 @@ public final class RotationLockControllerImpl implements RotationLockController
                && mDeviceStateRotationLockSettingController.isPresent()) {
                && mDeviceStateRotationLockSettingController.isPresent()) {
            mCallbacks.add(mDeviceStateRotationLockSettingController.get());
            mCallbacks.add(mDeviceStateRotationLockSettingController.get());
        }
        }
        mBgExecutor = bgExecutor;
        mMainExecutor = mainExecutor;


        setListening(true);
        setListening(true);
    }
    }
@@ -126,14 +135,35 @@ public final class RotationLockControllerImpl implements RotationLockController
    }
    }


    private void notifyChanged() {
    private void notifyChanged() {
        mBgExecutor.execute(() -> {
            boolean isRotationLocked = mRotationPolicy.isRotationLocked();
            boolean isRotationLockToggleVisible = mRotationPolicy.isRotationLockToggleVisible();
            for (RotationLockControllerCallback callback : mCallbacks) {
            for (RotationLockControllerCallback callback : mCallbacks) {
            notifyChanged(callback);
                mMainExecutor.execute(
                        () -> notifyChanged(callback, isRotationLocked, isRotationLockToggleVisible)
                );
            }
            }
        });
    }
    }


    private void notifyChanged(RotationLockControllerCallback callback) {
    private void notifyChanged(RotationLockControllerCallback callback) {
        callback.onRotationLockStateChanged(mRotationPolicy.isRotationLocked(),
        mBgExecutor.execute(() -> {
                mRotationPolicy.isRotationLockToggleVisible());
            boolean isRotationLocked = mRotationPolicy.isRotationLocked();
            boolean isRotationLockToggleVisible = mRotationPolicy.isRotationLockToggleVisible();
            mMainExecutor.execute(
                    () -> notifyChanged(callback, isRotationLocked, isRotationLockToggleVisible)
            );
        });
    }

    @MainThread
    // This should be called in main thread as consumers expect it.
    private void notifyChanged(
            RotationLockControllerCallback callback,
            boolean isRotationLocked,
            boolean isRotationLockToggleVisible
    ) {
        callback.onRotationLockStateChanged(isRotationLocked, isRotationLockToggleVisible);
    }
    }


    public static boolean hasSufficientPermission(Context context) {
    public static boolean hasSufficientPermission(Context context) {