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

Commit dd0fe227 authored by Paul Colta's avatar Paul Colta
Browse files

HDMI: Add atom logging for power state change on <AS> lost toggle

Test: atest com.android.server.hdmi
Flag: EXEMPT atom definition
Bug: 379130869
Bug: 332780751
Change-Id: If595a41ae71ef64fe70f699c8980365849667cc3
parent 3161f3e1
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -265,6 +265,26 @@ public class HdmiCecAtomWriter {
                enumLogReason);
    }

    /**
     * Writes a HdmiPowerStateChangeOnActiveSourceLostToggled atom representing a
     * HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST setting change.
     * @param isEnabled           Whether the setting is enabled.
     * @param enumLogReason       The event that triggered the log.
     * @param manufacturerPnpId   Manufacturer PNP ID reported in the EDID.
     * @param manufacturerYear    Manufacture year reported in the EDID.
     * @param manufacturerWeek    Manufacture week reporter in the EDID.
     */
    public void powerStateChangeOnActiveSourceLostChanged(boolean isEnabled, int enumLogReason,
            String manufacturerPnpId, int manufacturerYear, int manufacturerWeek) {
        FrameworkStatsLog.write(
                FrameworkStatsLog.HDMI_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLED,
                isEnabled,
                enumLogReason,
                manufacturerPnpId,
                manufacturerYear,
                manufacturerWeek);
    }

    private int earcStateToEnum(int earcState) {
        switch (earcState) {
            case HDMI_EARC_STATUS_IDLE:
+16 −0
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.hardware.display.DeviceProductInfo;
import android.hardware.hdmi.HdmiControlManager;
import android.hardware.hdmi.HdmiDeviceInfo;
import android.hardware.hdmi.IHdmiControlCallback;
@@ -31,6 +32,7 @@ import android.os.PowerManager;
import android.os.SystemProperties;
import android.sysprop.HdmiProperties;
import android.util.Slog;
import android.view.Display;

import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.LocalePicker;
@@ -82,6 +84,8 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
    // lost.
    private Handler mDelayedPopupOnActiveSourceLostHandler;

    private boolean mIsActiveSourceLostPopupLaunched;

    // Determines what action should be taken upon receiving Routing Control messages.
    @VisibleForTesting
    protected HdmiProperties.playback_device_action_on_routing_control_values
@@ -96,6 +100,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
        mDelayedStandbyOnActiveSourceLostHandler = new Handler(service.getServiceLooper());
        mDelayedPopupOnActiveSourceLostHandler = new Handler(service.getServiceLooper());
        mStandbyHandler = new HdmiCecStandbyModeHandler(service, this);
        mIsActiveSourceLostPopupLaunched = false;
    }

    @Override
@@ -275,6 +280,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
        public void run() {
            if (!isActiveSource()) {
                mService.standby();
                mIsActiveSourceLostPopupLaunched = false;
            }
        }
    }
@@ -283,6 +289,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
    void dismissUiOnActiveSourceStatusRecovered() {
        assertRunOnServiceThread();
        Intent intent = new Intent(HdmiControlManager.ACTION_ON_ACTIVE_SOURCE_RECOVERED_DISMISS_UI);
        mIsActiveSourceLostPopupLaunched = false;
        mService.sendBroadcastAsUser(intent);
    }

@@ -516,6 +523,7 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
                    )));
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivityAsUser(intent, context.getUser());
            mIsActiveSourceLostPopupLaunched = true;
        } catch (ActivityNotFoundException e) {
            Slog.e(TAG, "Unable to start HdmiCecActiveSourceLostActivity");
        } finally {
@@ -733,6 +741,14 @@ public class HdmiCecLocalDevicePlayback extends HdmiCecLocalDeviceSource {
        return Constants.ADDR_TV;
    }

    boolean isActiveSourceLostPopupLaunched() {
        return mIsActiveSourceLostPopupLaunched;
    }

    void setIsActiveSourceLostPopupLaunched(boolean isActiveSourceLostPopupLaunched) {
        mIsActiveSourceLostPopupLaunched = isActiveSourceLostPopupLaunched;
    }

    @Override
    @ServiceThreadOnly
    protected void disableDevice(boolean initiatedByCec, PendingActionClearedCallback callback) {
+46 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.hardware.display.DeviceProductInfo;
import android.hardware.display.DisplayManager;
import android.hardware.hdmi.DeviceFeatures;
import android.hardware.hdmi.HdmiControlManager;
@@ -106,6 +107,7 @@ import android.util.Slog;
import android.util.SparseArray;
import android.view.Display;
import android.view.KeyEvent;
import android.view.WindowManager;

import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
@@ -1008,6 +1010,21 @@ public class HdmiControlService extends SystemService {
                    }
                }, mServiceThreadExecutor);

        if (isPlaybackDevice()) {
            mHdmiCecConfig.registerChangeListener(
                    HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST,
                    new HdmiCecConfig.SettingChangeListener() {
                        @Override
                        public void onChange(String setting) {
                            boolean goToStandbyOnActiveSourceLost =
                                    mHdmiCecConfig.getStringValue(
                                            HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST)
                                            .equals(HdmiControlManager.POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_STANDBY_NOW);
                            writePowerStateChangeOnActiveSourceLostAtom(goToStandbyOnActiveSourceLost);
                        }
                    }, mServiceThreadExecutor);
        }

        mDeviceConfig.addOnPropertiesChangedListener(getContext().getMainExecutor(),
                new DeviceConfig.OnPropertiesChangedListener() {
                    @Override
@@ -3190,6 +3207,7 @@ public class HdmiControlService extends SystemService {
            // Cancel an existing timer to send the device to sleep since OTP was triggered.
            playback().mDelayedStandbyOnActiveSourceLostHandler
                    .removeCallbacksAndMessages(null);
            playback().setIsActiveSourceLostPopupLaunched(false);
        }

        if (source == null) {
@@ -5227,6 +5245,34 @@ public class HdmiControlService extends SystemService {
                String.valueOf(value));
    }

    /**
     * Writes a HdmiPowerStateChangeOnActiveSourceLostToggled atom representing a
     * HdmiControlManager.CEC_SETTING_NAME_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST setting change.
     */
    protected void writePowerStateChangeOnActiveSourceLostAtom(boolean isSettingEnabled) {
        String manufacturerPnpId = "undefined";
        int manufactureYear = -1;
        int manufactureWeek = -1;
        Display display = getContext().getDisplay();
        if (display != null) {
            DeviceProductInfo deviceProductInfo = display.getDeviceProductInfo();
            manufacturerPnpId = deviceProductInfo.getManufacturerPnpId();
            manufactureYear = deviceProductInfo.getManufactureYear();
        }
        int enumLogReason =
                HdmiStatsEnums.LOG_REASON_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLE_UNKNOWN;
        if (playback() != null) {
            if (playback().isActiveSourceLostPopupLaunched()) {
                enumLogReason = HdmiStatsEnums.LOG_REASON_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLE_POP_UP;
            } else {
                enumLogReason = HdmiStatsEnums.LOG_REASON_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLE_SETTING;
            }
        }

        getAtomWriter().powerStateChangeOnActiveSourceLostChanged(isSettingEnabled, enumLogReason,
                manufacturerPnpId, manufactureYear, manufactureWeek);
    }

    /**
     * Reads the property that checks if CEC was enabled by the user while in offline mode such that
     * it won't be disabled when going to sleep by low energy mode.
+17 −0
Original line number Diff line number Diff line
@@ -433,4 +433,21 @@ public class HdmiCecAtomLoggingTest {
                .dsmStatusChanged(anyBoolean(), anyBoolean(),
                        eq(HdmiStatsEnums.LOG_REASON_DSM_SETTING_TOGGLED));
    }

    @Test
    public void testPowerStateChangeOnActiveSourceLostToggled_writesAtom_logReasonSetting() {
        mHdmiControlServiceSpy.onWakeUp(WAKE_UP_SCREEN_ON);
        Mockito.clearInvocations(mHdmiCecAtomWriterSpy);
        mTestLooper.dispatchAll();

        mHdmiControlServiceSpy.writePowerStateChangeOnActiveSourceLostAtom(true);
        mTestLooper.dispatchAll();

        verify(mHdmiCecAtomWriterSpy, times(1))
                .powerStateChangeOnActiveSourceLostChanged(eq(true),
                        eq(HdmiStatsEnums.LOG_REASON_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLE_SETTING), anyString(), anyInt(), anyInt());
        verify(mHdmiCecAtomWriterSpy, never())
                .powerStateChangeOnActiveSourceLostChanged(eq(true),
                        eq(HdmiStatsEnums.LOG_REASON_POWER_STATE_CHANGE_ON_ACTIVE_SOURCE_LOST_TOGGLE_POP_UP), anyString(), anyInt(), anyInt());
    }
}
+15 −18
Original line number Diff line number Diff line
@@ -95,9 +95,6 @@ public class HdmiCecLocalDevicePlaybackTest {
    private boolean mActiveMediaSessionsPaused;
    private FakePowerManagerInternalWrapper mPowerManagerInternal =
            new FakePowerManagerInternalWrapper();

    private boolean mIsOnActiveSourceLostPopupActive;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
@@ -165,12 +162,12 @@ public class HdmiCecLocalDevicePlaybackTest {
        mHdmiCecLocalDevicePlayback = new HdmiCecLocalDevicePlayback(mHdmiControlService) {
            @Override
            void startHdmiCecActiveSourceLostActivity() {
                mIsOnActiveSourceLostPopupActive = true;
                setIsActiveSourceLostPopupLaunched(true);
            }

            @Override
            void dismissUiOnActiveSourceStatusRecovered() {
                mIsOnActiveSourceLostPopupActive = false;
                setIsActiveSourceLostPopupLaunched(false);
            }
        };
        mHdmiCecLocalDevicePlayback.init();
@@ -2389,7 +2386,7 @@ public class HdmiCecLocalDevicePlaybackTest {
        mTestLooper.dispatchAll();

        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress).isEqualTo(ADDR_TV);
        assertThat(mIsOnActiveSourceLostPopupActive).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue();
    }

    @Test
@@ -2430,7 +2427,7 @@ public class HdmiCecLocalDevicePlaybackTest {

        // Pop-up is not shown, playback device asserts active source since TV doesn't answer the
        // request.
        assertThat(mIsOnActiveSourceLostPopupActive).isFalse();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse();
        assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress)
                .isEqualTo(mPlaybackLogicalAddress);
@@ -2480,7 +2477,7 @@ public class HdmiCecLocalDevicePlaybackTest {
        mTestLooper.dispatchAll();

        // Pop-up is not shown since playback device is active source.
        assertThat(mIsOnActiveSourceLostPopupActive).isFalse();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse();
        assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress)
                .isEqualTo(mPlaybackLogicalAddress);
@@ -2532,7 +2529,7 @@ public class HdmiCecLocalDevicePlaybackTest {

        // Pop-up is shown, playback device doesn't assert active source since active path is
        // switched to a non-CEC device.
        assertThat(mIsOnActiveSourceLostPopupActive).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress)
                .isEqualTo(ADDR_INVALID);
        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().physicalAddress)
@@ -2569,7 +2566,7 @@ public class HdmiCecLocalDevicePlaybackTest {
        });
        mTestLooper.dispatchAll();

        assertThat(mIsOnActiveSourceLostPopupActive).isFalse();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse();
        assertThat(mPowerManager.isInteractive()).isTrue();
        assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress)
@@ -2609,13 +2606,13 @@ public class HdmiCecLocalDevicePlaybackTest {
        mNativeWrapper.onCecMessage(activeSourceFromTv);
        mTestLooper.dispatchAll();

        assertThat(mIsOnActiveSourceLostPopupActive).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue();

        assertThat(mHdmiCecLocalDevicePlayback.handleSetStreamPath(setStreamPathToPlayback))
                .isEqualTo(Constants.HANDLED);
        mTestLooper.dispatchAll();

        assertThat(mIsOnActiveSourceLostPopupActive).isFalse();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse();
        assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress)
                .isEqualTo(mPlaybackLogicalAddress);
@@ -2664,13 +2661,13 @@ public class HdmiCecLocalDevicePlaybackTest {
        // Pop-up is triggered.
        mTestLooper.moveTimeForward(POPUP_AFTER_ACTIVE_SOURCE_LOST_DELAY_MS);
        mTestLooper.dispatchAll();
        assertThat(mIsOnActiveSourceLostPopupActive).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue();

        assertThat(mHdmiCecLocalDevicePlayback.handleRoutingChange(routingChangeToPlayback))
                .isEqualTo(Constants.HANDLED);
        mTestLooper.dispatchAll();

        assertThat(mIsOnActiveSourceLostPopupActive).isFalse();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse();
        assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress)
                .isEqualTo(mPlaybackLogicalAddress);
@@ -2711,7 +2708,7 @@ public class HdmiCecLocalDevicePlaybackTest {
        mNativeWrapper.onCecMessage(activeSourceFromTv);
        mTestLooper.dispatchAll();

        assertThat(mIsOnActiveSourceLostPopupActive).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue();
        mHdmiControlService.oneTouchPlay(new IHdmiControlCallback() {
            @Override
            public void onComplete(int result) throws RemoteException {
@@ -2724,7 +2721,7 @@ public class HdmiCecLocalDevicePlaybackTest {
        });
        mTestLooper.dispatchAll();

        assertThat(mIsOnActiveSourceLostPopupActive).isFalse();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse();
        assertThat(mNativeWrapper.getResultMessages().contains(activeSourceFromPlayback)).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.getActiveSource().logicalAddress)
                .isEqualTo(mPlaybackLogicalAddress);
@@ -2897,11 +2894,11 @@ public class HdmiCecLocalDevicePlaybackTest {
            } else {
                mTestLooper.moveTimeForward(TIMEOUT_MS);
                mTestLooper.dispatchAll();
                assertThat(mIsOnActiveSourceLostPopupActive).isFalse();
                assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isFalse();
                return;
            }
        }
        assertThat(mIsOnActiveSourceLostPopupActive).isTrue();
        assertThat(mHdmiCecLocalDevicePlayback.isActiveSourceLostPopupLaunched()).isTrue();

        mPowerManagerInternal.setIdleDuration(idleDuration);
        mTestLooper.moveTimeForward(STANDBY_AFTER_ACTIVE_SOURCE_LOST_DELAY_MS);