diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index cede2738cff07..70d722d4f65c6 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -1577,6 +1577,10 @@ public class HdmiControlService extends SystemService { // If the device is not TV, we can't convert path to port-id, so stop here. return true; } + // Invalidate the physical address if parameters length is too short. + if (params.length < offset + 2) { + return false; + } int path = HdmiUtils.twoBytesToInt(params, offset); if (path != Constants.INVALID_PHYSICAL_ADDRESS && path == getPhysicalAddress()) { return true; diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTvTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTvTest.java new file mode 100644 index 0000000000000..920c376d5dfb0 --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiControlServiceTvTest.java @@ -0,0 +1,142 @@ +/* + * Copyright (C) 2023 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.hdmi; + +import static com.android.server.SystemService.PHASE_SYSTEM_SERVICES_READY; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.hardware.hdmi.HdmiDeviceInfo; +import android.os.Looper; +import android.os.test.TestLooper; +import android.platform.test.annotations.Presubmit; + +import androidx.test.InstrumentationRegistry; +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.util.Collections; + +/** + * TV specific tests for {@link HdmiControlService} class. + */ +@SmallTest +@Presubmit +@RunWith(JUnit4.class) +public class HdmiControlServiceTvTest { + + private static final String TAG = "HdmiControlServiceTvTest"; + private HdmiControlService mHdmiControlService; + private HdmiCecController mHdmiCecController; + private FakeNativeWrapper mNativeWrapper; + private HdmiEarcController mHdmiEarcController; + private FakeEarcNativeWrapper mEarcNativeWrapper; + private Looper mMyLooper; + private TestLooper mTestLooper = new TestLooper(); + + @Before + public void setUp() throws Exception { + Context context = InstrumentationRegistry.getTargetContext(); + mMyLooper = mTestLooper.getLooper(); + + FakeAudioFramework audioFramework = new FakeAudioFramework(); + + mHdmiControlService = + new HdmiControlService(InstrumentationRegistry.getTargetContext(), + Collections.singletonList(HdmiDeviceInfo.DEVICE_TV), + audioFramework.getAudioManager(), + audioFramework.getAudioDeviceVolumeManager()) { + @Override + int pathToPortId(int path) { + return Constants.INVALID_PORT_ID + 1; + } + }; + + mMyLooper = mTestLooper.getLooper(); + mHdmiControlService.setIoLooper(mMyLooper); + mHdmiControlService.setHdmiCecConfig(new FakeHdmiCecConfig(context)); + mHdmiControlService.setDeviceConfig(new FakeDeviceConfigWrapper()); + mHdmiControlService.onBootPhase(PHASE_SYSTEM_SERVICES_READY); + + mNativeWrapper = new FakeNativeWrapper(); + mHdmiCecController = HdmiCecController.createWithNativeWrapper( + mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); + mHdmiControlService.setCecController(mHdmiCecController); + mEarcNativeWrapper = new FakeEarcNativeWrapper(); + mHdmiEarcController = HdmiEarcController.createWithNativeWrapper( + mHdmiControlService, mEarcNativeWrapper); + mHdmiControlService.setEarcController(mHdmiEarcController); + mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create( + mHdmiControlService)); + mHdmiControlService.initService(); + + mTestLooper.dispatchAll(); + } + + @Test + public void onCecMessage_shortPhysicalAddress_featureAbortInvalidOperand() { + // Invalid message. + HdmiCecMessage message = HdmiUtils.buildMessage("40:9D:14"); + + mNativeWrapper.onCecMessage(message); + mTestLooper.dispatchAll(); + + HdmiCecMessage featureAbort = HdmiCecMessageBuilder.buildFeatureAbortCommand( + Constants.ADDR_TV, Constants.ADDR_PLAYBACK_1, Constants.MESSAGE_INACTIVE_SOURCE, + Constants.ABORT_INVALID_OPERAND); + assertThat(mNativeWrapper.getResultMessages()).contains(featureAbort); + } + + @Test + public void handleCecCommand_shortPhysicalAddress_returnsAbortInvalidOperand() { + // Invalid message. + HdmiCecMessage message = HdmiUtils.buildMessage("4F:82:10"); + + // In case of a broadcasted message is not expected. + // See CEC 1.4b specification, 12.2 Protocol General Rules for detail. + assertThat(mHdmiControlService.handleCecCommand(message)) + .isEqualTo(Constants.ABORT_INVALID_OPERAND); + } + + @Test + public void test_verifyPhysicalAddresses() { + // + assertThat(mHdmiControlService + .verifyPhysicalAddresses(HdmiUtils.buildMessage("0F:80:10:00:40:00"))).isTrue(); + assertThat(mHdmiControlService + .verifyPhysicalAddresses(HdmiUtils.buildMessage("0F:80:10:00:40"))).isFalse(); + assertThat(mHdmiControlService + .verifyPhysicalAddresses(HdmiUtils.buildMessage("0F:80:10"))).isFalse(); + + // + assertThat(mHdmiControlService + .verifyPhysicalAddresses(HdmiUtils.buildMessage("40:70:00:00"))).isTrue(); + assertThat(mHdmiControlService + .verifyPhysicalAddresses(HdmiUtils.buildMessage("40:70:00"))).isFalse(); + + // + assertThat(mHdmiControlService + .verifyPhysicalAddresses(HdmiUtils.buildMessage("4F:82:10:00"))).isTrue(); + assertThat(mHdmiControlService + .verifyPhysicalAddresses(HdmiUtils.buildMessage("4F:82:10"))).isFalse(); + } +}