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

Commit 3c16351a authored by Fiona Campbell's avatar Fiona Campbell Committed by Android (Google) Code Review
Browse files

Merge "Migrate mocking power tests" into main

parents 2a06ffd2 44127aaf
Loading
Loading
Loading
Loading
+0 −316
Original line number Diff line number Diff line
/*
 * 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.power;

import static com.google.common.truth.Truth.assertThat;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.app.ActivityManagerInternal;
import android.attention.AttentionManagerInternal;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Resources;
import android.hardware.SensorManager;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.DisplayManagerInternal;
import android.os.BatteryManagerInternal;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
import android.os.PowerSaveState;
import android.os.test.TestLooper;
import android.provider.Settings;
import android.service.dreams.DreamManagerInternal;
import android.test.mock.MockContentResolver;
import android.view.Display;
import android.view.DisplayInfo;

import androidx.test.InstrumentationRegistry;

import com.android.internal.app.IBatteryStats;
import com.android.internal.util.test.FakeSettingsProvider;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.lights.LightsManager;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.power.PowerManagerService.BatteryReceiver;
import com.android.server.power.PowerManagerService.Injector;
import com.android.server.power.PowerManagerService.NativeWrapper;
import com.android.server.power.PowerManagerService.UserSwitchedReceiver;
import com.android.server.power.batterysaver.BatterySaverController;
import com.android.server.power.batterysaver.BatterySaverPolicy;
import com.android.server.power.batterysaver.BatterySaverStateMachine;
import com.android.server.power.batterysaver.BatterySavingStats;
import com.android.server.testutils.OffsettableClock;

import java.util.concurrent.Executor;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

/**
 * Tests for {@link com.android.server.power.PowerManagerService}.
 *
 * Build/Install/Run:
 *  atest FrameworksServicesTests:PowerManagerServiceMockingTest
 */
public class PowerManagerServiceMockingTest {
    private static final String SYSTEM_PROPERTY_QUIESCENT = "ro.boot.quiescent";
    private static final String SYSTEM_PROPERTY_REBOOT_REASON = "sys.boot.reason";

    private static final float BRIGHTNESS_FACTOR = 0.7f;
    private static final boolean BATTERY_SAVER_ENABLED = true;

    @Mock private BatterySaverController mBatterySaverControllerMock;
    @Mock private BatterySaverPolicy mBatterySaverPolicyMock;
    @Mock private BatterySaverStateMachine mBatterySaverStateMachineMock;
    @Mock private LightsManager mLightsManagerMock;
    @Mock private DisplayManagerInternal mDisplayManagerInternalMock;
    @Mock private BatteryManagerInternal mBatteryManagerInternalMock;
    @Mock private ActivityManagerInternal mActivityManagerInternalMock;
    @Mock private AttentionManagerInternal mAttentionManagerInternalMock;
    @Mock private DreamManagerInternal mDreamManagerInternalMock;
    @Mock private PowerManagerService.NativeWrapper mNativeWrapperMock;
    @Mock private Notifier mNotifierMock;
    @Mock private WirelessChargerDetector mWirelessChargerDetectorMock;
    @Mock private AmbientDisplayConfiguration mAmbientDisplayConfigurationMock;
    @Mock private SystemPropertiesWrapper mSystemPropertiesMock;
    @Mock private DeviceStateManager mDeviceStateManagerMock;

    @Mock
    private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;

    private PowerManagerService mService;
    private PowerSaveState mPowerSaveState;
    private ContextWrapper mContextSpy;
    private BatteryReceiver mBatteryReceiver;
    private UserSwitchedReceiver mUserSwitchedReceiver;
    private Resources mResourcesSpy;
    private OffsettableClock mClock;
    private TestLooper mTestLooper;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        FakeSettingsProvider.clearSettingsProvider();

        mPowerSaveState = new PowerSaveState.Builder()
                .setBatterySaverEnabled(BATTERY_SAVER_ENABLED)
                .setBrightnessFactor(BRIGHTNESS_FACTOR)
                .build();
        when(mBatterySaverPolicyMock.getBatterySaverPolicy(
                eq(PowerManager.ServiceType.SCREEN_BRIGHTNESS)))
                .thenReturn(mPowerSaveState);
        when(mBatteryManagerInternalMock.isPowered(anyInt())).thenReturn(false);
        when(mInattentiveSleepWarningControllerMock.isShown()).thenReturn(false);
        when(mDisplayManagerInternalMock.requestPowerState(anyInt(), any(), anyBoolean()))
                .thenReturn(true);
        when(mSystemPropertiesMock.get(eq(SYSTEM_PROPERTY_QUIESCENT), anyString())).thenReturn("");
        when(mAmbientDisplayConfigurationMock.ambientDisplayAvailable()).thenReturn(true);

        addLocalServiceMock(LightsManager.class, mLightsManagerMock);
        addLocalServiceMock(DisplayManagerInternal.class, mDisplayManagerInternalMock);
        addLocalServiceMock(BatteryManagerInternal.class, mBatteryManagerInternalMock);
        addLocalServiceMock(ActivityManagerInternal.class, mActivityManagerInternalMock);
        addLocalServiceMock(AttentionManagerInternal.class, mAttentionManagerInternalMock);
        addLocalServiceMock(DreamManagerInternal.class, mDreamManagerInternalMock);

        mContextSpy = spy(new ContextWrapper(InstrumentationRegistry.getContext()));
        mResourcesSpy = spy(mContextSpy.getResources());
        when(mContextSpy.getResources()).thenReturn(mResourcesSpy);

        MockContentResolver cr = new MockContentResolver(mContextSpy);
        cr.addProvider(Settings.AUTHORITY, new FakeSettingsProvider());
        when(mContextSpy.getContentResolver()).thenReturn(cr);

        when(mContextSpy.getSystemService(DeviceStateManager.class))
                .thenReturn(mDeviceStateManagerMock);

        Settings.Global.putInt(mContextSpy.getContentResolver(),
                Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0);

        mClock = new OffsettableClock.Stopped();
        mTestLooper = new TestLooper(mClock::now);
    }

    private PowerManagerService createService() {
        mService = new PowerManagerService(mContextSpy, new Injector() {
            @Override
            Notifier createNotifier(Looper looper, Context context, IBatteryStats batteryStats,
                    SuspendBlocker suspendBlocker, WindowManagerPolicy policy,
                    FaceDownDetector faceDownDetector, ScreenUndimDetector screenUndimDetector,
                    Executor executor) {
                return mNotifierMock;
            }

            @Override
            SuspendBlocker createSuspendBlocker(PowerManagerService service, String name) {
                return super.createSuspendBlocker(service, name);
            }

            @Override
            BatterySaverPolicy createBatterySaverPolicy(
                    Object lock, Context context, BatterySavingStats batterySavingStats) {
                return mBatterySaverPolicyMock;
            }

            @Override
            BatterySaverController createBatterySaverController(
                    Object lock, Context context, BatterySaverPolicy batterySaverPolicy,
                    BatterySavingStats batterySavingStats) {
                return mBatterySaverControllerMock;
            }

            @Override
            BatterySaverStateMachine createBatterySaverStateMachine(Object lock, Context context,
                    BatterySaverController batterySaverController) {
                return mBatterySaverStateMachineMock;
            }

            @Override
            NativeWrapper createNativeWrapper() {
                return mNativeWrapperMock;
            }

            @Override
            WirelessChargerDetector createWirelessChargerDetector(
                    SensorManager sensorManager, SuspendBlocker suspendBlocker, Handler handler) {
                return mWirelessChargerDetectorMock;
            }

            @Override
            AmbientDisplayConfiguration createAmbientDisplayConfiguration(Context context) {
                return mAmbientDisplayConfigurationMock;
            }

            @Override
            InattentiveSleepWarningController createInattentiveSleepWarningController() {
                return mInattentiveSleepWarningControllerMock;
            }

            @Override
            public SystemPropertiesWrapper createSystemPropertiesWrapper() {
                return mSystemPropertiesMock;
            }

            @Override
            PowerManagerService.Clock createClock() {
                return new PowerManagerService.Clock() {
                    @Override
                    public long uptimeMillis() {
                        return mClock.now();
                    }

                    @Override
                    public long elapsedRealtime() {
                        return mClock.now();
                    }
                };
            }

            @Override
            Handler createHandler(Looper looper, Handler.Callback callback) {
                return new Handler(mTestLooper.getLooper(), callback);
            }

            @Override
            void invalidateIsInteractiveCaches() {
                // Avoids an SELinux failure.
            }
        });
        return mService;
    }

    @After
    public void tearDown() throws Exception {
        LocalServices.removeServiceForTest(LightsManager.class);
        LocalServices.removeServiceForTest(DisplayManagerInternal.class);
        LocalServices.removeServiceForTest(BatteryManagerInternal.class);
        LocalServices.removeServiceForTest(ActivityManagerInternal.class);
        LocalServices.removeServiceForTest(AttentionManagerInternal.class);
        LocalServices.removeServiceForTest(DreamManagerInternal.class);
        FakeSettingsProvider.clearSettingsProvider();
    }

    /**
     * Creates a mock and registers it to {@link LocalServices}.
     */
    private static <T> void addLocalServiceMock(Class<T> clazz, T mock) {
        LocalServices.removeServiceForTest(clazz);
        LocalServices.addService(clazz, mock);
    }

    private void advanceTime(long timeMs) {
        mClock.fastForward(timeMs);
        mTestLooper.dispatchAll();
    }

    @Test
    public void testUserActivityOnDeviceStateChange() {
        createService();
        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);

        final DisplayInfo info = new DisplayInfo();
        info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
        when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);

        final ArgumentCaptor<DeviceStateCallback> deviceStateCallbackCaptor =
                ArgumentCaptor.forClass(DeviceStateCallback.class);
        verify(mDeviceStateManagerMock).registerCallback(any(),
                deviceStateCallbackCaptor.capture());

        // Advance the time 10001 and verify that the device thinks it has been idle
        // for just less than that.
        mService.onUserActivity();
        advanceTime(10001);
        assertThat(mService.wasDeviceIdleForInternal(10000)).isTrue();

        // Send a display state change event and advance the clock 10.
        final DeviceStateCallback deviceStateCallback = deviceStateCallbackCaptor.getValue();
        deviceStateCallback.onStateChanged(1);
        final long timeToAdvance = 10;
        advanceTime(timeToAdvance);

        // Ensure that the device has been idle for only 10 (doesn't include the idle time
        // before the display state event).
        assertThat(mService.wasDeviceIdleForInternal(timeToAdvance - 1)).isTrue();
        assertThat(mService.wasDeviceIdleForInternal(timeToAdvance)).isFalse();

        // Send the same state and ensure that does not trigger an update.
        deviceStateCallback.onStateChanged(1);
        advanceTime(timeToAdvance);
        final long newTime = timeToAdvance * 2;

        assertThat(mService.wasDeviceIdleForInternal(newTime - 1)).isTrue();
        assertThat(mService.wasDeviceIdleForInternal(newTime)).isFalse();
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -23,6 +23,10 @@ android_test {
        "android.test.mock",
    ],

    defaults: [
        "modules-utils-testable-device-config-defaults",
    ],

    platform_apis: true,
    test_suites: [
        "device-tests",
+0 −1
Original line number Diff line number Diff line
@@ -2,4 +2,3 @@

include /services/core/java/com/android/server/power/OWNERS
per-file ThermalManagerServiceTest.java=wvw@google.com, xwxw@google.com
 No newline at end of file
+47 −0
Original line number Diff line number Diff line
@@ -60,6 +60,8 @@ import android.content.IntentFilter;
import android.content.PermissionChecker;
import android.content.res.Resources;
import android.hardware.SensorManager;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.devicestate.DeviceStateManager.DeviceStateCallback;
import android.hardware.display.AmbientDisplayConfiguration;
import android.hardware.display.DisplayManagerInternal;
import android.hardware.display.DisplayManagerInternal.DisplayPowerRequest;
@@ -160,6 +162,7 @@ public class PowerManagerServiceTest {
    @Mock private InattentiveSleepWarningController mInattentiveSleepWarningControllerMock;
    @Mock private PowerManagerService.PermissionCheckerWrapper mPermissionCheckerWrapperMock;
    @Mock private PowerManagerService.PowerPropertiesWrapper mPowerPropertiesWrapper;
    @Mock private DeviceStateManager mDeviceStateManagerMock;

    @Rule public TestRule compatChangeRule = new PlatformCompatChangeRule();

@@ -2710,4 +2713,48 @@ public class PowerManagerServiceTest {
        verify(mNotifierMock, never()).onUserActivity(anyInt(),  anyInt(), anyInt());
    }

    @Test
    public void testUserActivityOnDeviceStateChange() {
        when(mContextSpy.getSystemService(DeviceStateManager.class))
                .thenReturn(mDeviceStateManagerMock);

        createService();
        mService.onBootPhase(SystemService.PHASE_SYSTEM_SERVICES_READY);
        mService.onBootPhase(SystemService.PHASE_BOOT_COMPLETED);

        final DisplayInfo info = new DisplayInfo();
        info.displayGroupId = Display.DEFAULT_DISPLAY_GROUP;
        when(mDisplayManagerInternalMock.getDisplayInfo(Display.DEFAULT_DISPLAY)).thenReturn(info);

        final ArgumentCaptor<DeviceStateCallback> deviceStateCallbackCaptor =
                ArgumentCaptor.forClass(DeviceStateCallback.class);
        verify(mDeviceStateManagerMock).registerCallback(any(),
                deviceStateCallbackCaptor.capture());

        // Advance the time 10001 and verify that the device thinks it has been idle
        // for just less than that.
        mService.onUserActivity();
        advanceTime(10001);
        assertThat(mService.wasDeviceIdleForInternal(10000)).isTrue();

        // Send a display state change event and advance the clock 10.
        final DeviceStateCallback deviceStateCallback = deviceStateCallbackCaptor.getValue();
        deviceStateCallback.onStateChanged(1);
        final long timeToAdvance = 10;
        advanceTime(timeToAdvance);

        // Ensure that the device has been idle for only 10 (doesn't include the idle time
        // before the display state event).
        assertThat(mService.wasDeviceIdleForInternal(timeToAdvance - 1)).isTrue();
        assertThat(mService.wasDeviceIdleForInternal(timeToAdvance)).isFalse();

        // Send the same state and ensure that does not trigger an update.
        deviceStateCallback.onStateChanged(1);
        advanceTime(timeToAdvance);
        final long newTime = timeToAdvance * 2;

        assertThat(mService.wasDeviceIdleForInternal(newTime - 1)).isTrue();
        assertThat(mService.wasDeviceIdleForInternal(newTime)).isFalse();
    }

}