Loading services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +8 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.hdmi; import android.annotation.Nullable; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.input.InputManager; import android.os.Handler; Loading @@ -31,6 +32,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import com.android.server.hdmi.HdmiControlService.SendMessageCallback; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; Loading Loading @@ -249,11 +251,11 @@ abstract class HdmiCecLocalDevice { case Constants.MESSAGE_SET_MENU_LANGUAGE: return handleSetMenuLanguage(message); case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS: return handleGivePhysicalAddress(); return handleGivePhysicalAddress(null); case Constants.MESSAGE_GIVE_OSD_NAME: return handleGiveOsdName(message); case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID: return handleGiveDeviceVendorId(); return handleGiveDeviceVendorId(null); case Constants.MESSAGE_GET_CEC_VERSION: return handleGetCecVersion(message); case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS: Loading Loading @@ -325,23 +327,23 @@ abstract class HdmiCecLocalDevice { } @ServiceThreadOnly protected boolean handleGivePhysicalAddress() { protected boolean handleGivePhysicalAddress(@Nullable SendMessageCallback callback) { assertRunOnServiceThread(); int physicalAddress = mService.getPhysicalAddress(); HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( mAddress, physicalAddress, mDeviceType); mService.sendCecCommand(cecMessage); mService.sendCecCommand(cecMessage, callback); return true; } @ServiceThreadOnly protected boolean handleGiveDeviceVendorId() { protected boolean handleGiveDeviceVendorId(@Nullable SendMessageCallback callback) { assertRunOnServiceThread(); int vendorId = mService.getVendorId(); HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand( mAddress, vendorId); mService.sendCecCommand(cecMessage); mService.sendCecCommand(cecMessage, callback); return true; } Loading services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java +1 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,7 @@ import android.util.SparseArray; /** * A helper class to validates {@link HdmiCecMessage}. */ public final class HdmiCecMessageValidator { public class HdmiCecMessageValidator { private static final String TAG = "HdmiCecMessageValidator"; static final int OK = 0; Loading services/core/java/com/android/server/hdmi/HdmiControlService.java +31 −4 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.SystemService; Loading Loading @@ -290,6 +291,9 @@ public class HdmiControlService extends SystemService { @Nullable private PowerManager mPowerManager; @Nullable private Looper mIoLooper; // Last input port before switching to the MHL port. Should switch back to this port // when the mobile device sends the request one touch play with off. // Gets invalidated if we go to other port/input. Loading Loading @@ -383,13 +387,18 @@ public class HdmiControlService extends SystemService { @Override public void onStart() { if (mIoLooper == null) { mIoThread.start(); mIoLooper = mIoThread.getLooper(); } mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; mProhibitMode = false; mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); if (mCecController == null) { mCecController = HdmiCecController.create(this); } if (mCecController != null) { if (mHdmiControlEnabled) { initializeCec(INITIATED_BY_BOOT_UP); Loading @@ -406,7 +415,9 @@ public class HdmiControlService extends SystemService { mMhlDevices = Collections.emptyList(); initPortInfo(); if (mMessageValidator == null) { mMessageValidator = new HdmiCecMessageValidator(this); } publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); if (mCecController != null) { Loading @@ -424,6 +435,11 @@ public class HdmiControlService extends SystemService { mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED); } @VisibleForTesting void setCecController(HdmiCecController cecController) { mCecController = cecController; } @Override public void onBootPhase(int phase) { if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { Loading Loading @@ -747,8 +763,19 @@ public class HdmiControlService extends SystemService { * * <p>Declared as package-private. */ @Nullable Looper getIoLooper() { return mIoThread.getLooper(); return mIoLooper; } @VisibleForTesting void setIoLooper(Looper ioLooper) { mIoLooper = ioLooper; } @VisibleForTesting void setMessageValidator(HdmiCecMessageValidator messageValidator) { mMessageValidator = messageValidator; } /** Loading services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java 0 → 100644 +221 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV; import static com.android.server.hdmi.Constants.ADDR_BROADCAST; import static com.android.server.hdmi.Constants.ADDR_TV; import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED; import static com.android.server.hdmi.Constants.MESSAGE_DEVICE_VENDOR_ID; import static com.android.server.hdmi.Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import android.hardware.hdmi.HdmiPortInfo; import android.os.test.TestLooper; import android.support.test.filters.SmallTest; import android.os.MessageQueue; import com.android.server.hdmi.HdmiCecController.NativeWrapper; import junit.framework.Assert; import java.util.Arrays; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @SmallTest @RunWith(JUnit4.class) /** * Tests for {@link HdmiCecLocalDevice} class. */ public class HdmiCecLocalDeviceTest { private static final class NativeWrapperImpl implements NativeWrapper { @Override public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) { return 1L; } @Override public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body) { return SendCecCommandFactory(srcAddress, dstAddress, body); } @Override public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) { return 0; } @Override public void nativeClearLogicalAddress(long controllerPtr) { } @Override public int nativeGetPhysicalAddress(long controllerPtr) { return mPhysicalAddr; } @Override public int nativeGetVersion(long controllerPtr) { return 0; } @Override public int nativeGetVendorId(long controllerPtr) { return 0; } @Override public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) { return new HdmiPortInfo[0]; } @Override public void nativeSetOption(long controllerPtr, int flag, boolean enabled) { } @Override public void nativeSetLanguage(long controllerPtr, String language) { } @Override public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) { } @Override public boolean nativeIsConnected(long controllerPtr, int port) { return false; } } private static int SendCecCommandFactory(int srcAddress, int dstAddress, byte[] body) { switch(body[0] & 0xFF) { /** {@link Constants#MESSAGE_GIVE_PHYSICAL_ADDRESS} */ case MESSAGE_REPORT_PHYSICAL_ADDRESS: case MESSAGE_DEVICE_VENDOR_ID: return srcAddress == mSrcAddr && dstAddress == mDesAddr && Arrays.equals(Arrays.copyOfRange(body, 1, body.length), param)? 0 : 1; default: return 1; } } private class MyHdmiCecLocalDevice extends HdmiCecLocalDevice { protected MyHdmiCecLocalDevice(HdmiControlService service, int deviceType) { super(service, deviceType); } @Override protected void onAddressAllocated(int logicalAddress, int reason) { } @Override protected int getPreferredAddress() { return 0; } @Override protected void setPreferredAddress(int addr) { } } private MyHdmiCecLocalDevice mHdmiLocalDevice; private HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; private TestLooper mTestLooper = new TestLooper(); private static int mDesAddr = -1; private static int mSrcAddr = -1; private static int mPhysicalAddr = 2; private int callbackResult; private HdmiCecMessageValidator mMessageValidator; private static byte[] param; @Before public void SetUp() { mHdmiControlService = new HdmiControlService(null); mHdmiControlService.setIoLooper(mTestLooper.getLooper()); mHdmiCecController = HdmiCecController.createWithNativeWrapper( mHdmiControlService, new NativeWrapperImpl()); mHdmiControlService.setCecController(mHdmiCecController); mHdmiLocalDevice = new MyHdmiCecLocalDevice( mHdmiControlService, DEVICE_TV); mMessageValidator = new HdmiCecMessageValidator(mHdmiControlService){ @Override int isValid(HdmiCecMessage message) { return HdmiCecMessageValidator.OK; } }; mHdmiControlService.setMessageValidator(mMessageValidator); } @Test public void dispatchMessage_desNotValid() { HdmiCecMessage msg = new HdmiCecMessage( ADDR_TV, ADDR_TV, Constants.MESSAGE_CEC_VERSION, HdmiCecMessage.EMPTY_PARAM); boolean handleResult = mHdmiLocalDevice.dispatchMessage(msg); assertFalse(handleResult); } @Test public void handleGivePhysicalAddress_success() { mSrcAddr = ADDR_UNREGISTERED; mDesAddr = ADDR_BROADCAST; param = new byte[] { (byte) ((mPhysicalAddr >> 8) & 0xFF), (byte) (mPhysicalAddr & 0xFF), (byte) (DEVICE_TV & 0xFF) }; callbackResult = -1; boolean handleResult = mHdmiLocalDevice.handleGivePhysicalAddress( (int finalResult) -> callbackResult = finalResult); mTestLooper.dispatchAll(); /** * Test if CecMessage is sent successfully * SendMessageResult#SUCCESS is defined in HAL as 0 */ assertEquals(0, callbackResult); assertTrue(handleResult); } @Test public void handleGiveDeviceVendorId_success() { mSrcAddr = ADDR_UNREGISTERED; mDesAddr = ADDR_BROADCAST; /** nativeGetVendorId returns 0 */ param = new byte[] { (byte) ((0 >> 8) & 0xFF), (byte) (0 & 0xFF), (byte) (0 & 0xFF) }; callbackResult = -1; mHdmiLocalDevice.handleGiveDeviceVendorId( (int finalResult) -> callbackResult = finalResult); mTestLooper.dispatchAll(); assertEquals(0, callbackResult); } } Loading
services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java +8 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package com.android.server.hdmi; import android.annotation.Nullable; import android.hardware.hdmi.HdmiDeviceInfo; import android.hardware.input.InputManager; import android.os.Handler; Loading @@ -31,6 +32,7 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.util.IndentingPrintWriter; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; import com.android.server.hdmi.HdmiControlService.SendMessageCallback; import java.util.ArrayList; import java.util.Collections; import java.util.Iterator; Loading Loading @@ -249,11 +251,11 @@ abstract class HdmiCecLocalDevice { case Constants.MESSAGE_SET_MENU_LANGUAGE: return handleSetMenuLanguage(message); case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS: return handleGivePhysicalAddress(); return handleGivePhysicalAddress(null); case Constants.MESSAGE_GIVE_OSD_NAME: return handleGiveOsdName(message); case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID: return handleGiveDeviceVendorId(); return handleGiveDeviceVendorId(null); case Constants.MESSAGE_GET_CEC_VERSION: return handleGetCecVersion(message); case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS: Loading Loading @@ -325,23 +327,23 @@ abstract class HdmiCecLocalDevice { } @ServiceThreadOnly protected boolean handleGivePhysicalAddress() { protected boolean handleGivePhysicalAddress(@Nullable SendMessageCallback callback) { assertRunOnServiceThread(); int physicalAddress = mService.getPhysicalAddress(); HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand( mAddress, physicalAddress, mDeviceType); mService.sendCecCommand(cecMessage); mService.sendCecCommand(cecMessage, callback); return true; } @ServiceThreadOnly protected boolean handleGiveDeviceVendorId() { protected boolean handleGiveDeviceVendorId(@Nullable SendMessageCallback callback) { assertRunOnServiceThread(); int vendorId = mService.getVendorId(); HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand( mAddress, vendorId); mService.sendCecCommand(cecMessage); mService.sendCecCommand(cecMessage, callback); return true; } Loading
services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java +1 −1 Original line number Diff line number Diff line Loading @@ -22,7 +22,7 @@ import android.util.SparseArray; /** * A helper class to validates {@link HdmiCecMessage}. */ public final class HdmiCecMessageValidator { public class HdmiCecMessageValidator { private static final String TAG = "HdmiCecMessageValidator"; static final int OK = 0; Loading
services/core/java/com/android/server/hdmi/HdmiControlService.java +31 −4 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.SystemService; Loading Loading @@ -290,6 +291,9 @@ public class HdmiControlService extends SystemService { @Nullable private PowerManager mPowerManager; @Nullable private Looper mIoLooper; // Last input port before switching to the MHL port. Should switch back to this port // when the mobile device sends the request one touch play with off. // Gets invalidated if we go to other port/input. Loading Loading @@ -383,13 +387,18 @@ public class HdmiControlService extends SystemService { @Override public void onStart() { if (mIoLooper == null) { mIoThread.start(); mIoLooper = mIoThread.getLooper(); } mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON; mProhibitMode = false; mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true); mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); if (mCecController == null) { mCecController = HdmiCecController.create(this); } if (mCecController != null) { if (mHdmiControlEnabled) { initializeCec(INITIATED_BY_BOOT_UP); Loading @@ -406,7 +415,9 @@ public class HdmiControlService extends SystemService { mMhlDevices = Collections.emptyList(); initPortInfo(); if (mMessageValidator == null) { mMessageValidator = new HdmiCecMessageValidator(this); } publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService()); if (mCecController != null) { Loading @@ -424,6 +435,11 @@ public class HdmiControlService extends SystemService { mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED); } @VisibleForTesting void setCecController(HdmiCecController cecController) { mCecController = cecController; } @Override public void onBootPhase(int phase) { if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) { Loading Loading @@ -747,8 +763,19 @@ public class HdmiControlService extends SystemService { * * <p>Declared as package-private. */ @Nullable Looper getIoLooper() { return mIoThread.getLooper(); return mIoLooper; } @VisibleForTesting void setIoLooper(Looper ioLooper) { mIoLooper = ioLooper; } @VisibleForTesting void setMessageValidator(HdmiCecMessageValidator messageValidator) { mMessageValidator = messageValidator; } /** Loading
services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java 0 → 100644 +221 −0 Original line number Diff line number Diff line /* * Copyright (C) 2018 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 android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV; import static com.android.server.hdmi.Constants.ADDR_BROADCAST; import static com.android.server.hdmi.Constants.ADDR_TV; import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED; import static com.android.server.hdmi.Constants.MESSAGE_DEVICE_VENDOR_ID; import static com.android.server.hdmi.Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.Assert.assertTrue; import android.hardware.hdmi.HdmiPortInfo; import android.os.test.TestLooper; import android.support.test.filters.SmallTest; import android.os.MessageQueue; import com.android.server.hdmi.HdmiCecController.NativeWrapper; import junit.framework.Assert; import java.util.Arrays; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; @SmallTest @RunWith(JUnit4.class) /** * Tests for {@link HdmiCecLocalDevice} class. */ public class HdmiCecLocalDeviceTest { private static final class NativeWrapperImpl implements NativeWrapper { @Override public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) { return 1L; } @Override public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body) { return SendCecCommandFactory(srcAddress, dstAddress, body); } @Override public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) { return 0; } @Override public void nativeClearLogicalAddress(long controllerPtr) { } @Override public int nativeGetPhysicalAddress(long controllerPtr) { return mPhysicalAddr; } @Override public int nativeGetVersion(long controllerPtr) { return 0; } @Override public int nativeGetVendorId(long controllerPtr) { return 0; } @Override public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) { return new HdmiPortInfo[0]; } @Override public void nativeSetOption(long controllerPtr, int flag, boolean enabled) { } @Override public void nativeSetLanguage(long controllerPtr, String language) { } @Override public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) { } @Override public boolean nativeIsConnected(long controllerPtr, int port) { return false; } } private static int SendCecCommandFactory(int srcAddress, int dstAddress, byte[] body) { switch(body[0] & 0xFF) { /** {@link Constants#MESSAGE_GIVE_PHYSICAL_ADDRESS} */ case MESSAGE_REPORT_PHYSICAL_ADDRESS: case MESSAGE_DEVICE_VENDOR_ID: return srcAddress == mSrcAddr && dstAddress == mDesAddr && Arrays.equals(Arrays.copyOfRange(body, 1, body.length), param)? 0 : 1; default: return 1; } } private class MyHdmiCecLocalDevice extends HdmiCecLocalDevice { protected MyHdmiCecLocalDevice(HdmiControlService service, int deviceType) { super(service, deviceType); } @Override protected void onAddressAllocated(int logicalAddress, int reason) { } @Override protected int getPreferredAddress() { return 0; } @Override protected void setPreferredAddress(int addr) { } } private MyHdmiCecLocalDevice mHdmiLocalDevice; private HdmiControlService mHdmiControlService; private HdmiCecController mHdmiCecController; private TestLooper mTestLooper = new TestLooper(); private static int mDesAddr = -1; private static int mSrcAddr = -1; private static int mPhysicalAddr = 2; private int callbackResult; private HdmiCecMessageValidator mMessageValidator; private static byte[] param; @Before public void SetUp() { mHdmiControlService = new HdmiControlService(null); mHdmiControlService.setIoLooper(mTestLooper.getLooper()); mHdmiCecController = HdmiCecController.createWithNativeWrapper( mHdmiControlService, new NativeWrapperImpl()); mHdmiControlService.setCecController(mHdmiCecController); mHdmiLocalDevice = new MyHdmiCecLocalDevice( mHdmiControlService, DEVICE_TV); mMessageValidator = new HdmiCecMessageValidator(mHdmiControlService){ @Override int isValid(HdmiCecMessage message) { return HdmiCecMessageValidator.OK; } }; mHdmiControlService.setMessageValidator(mMessageValidator); } @Test public void dispatchMessage_desNotValid() { HdmiCecMessage msg = new HdmiCecMessage( ADDR_TV, ADDR_TV, Constants.MESSAGE_CEC_VERSION, HdmiCecMessage.EMPTY_PARAM); boolean handleResult = mHdmiLocalDevice.dispatchMessage(msg); assertFalse(handleResult); } @Test public void handleGivePhysicalAddress_success() { mSrcAddr = ADDR_UNREGISTERED; mDesAddr = ADDR_BROADCAST; param = new byte[] { (byte) ((mPhysicalAddr >> 8) & 0xFF), (byte) (mPhysicalAddr & 0xFF), (byte) (DEVICE_TV & 0xFF) }; callbackResult = -1; boolean handleResult = mHdmiLocalDevice.handleGivePhysicalAddress( (int finalResult) -> callbackResult = finalResult); mTestLooper.dispatchAll(); /** * Test if CecMessage is sent successfully * SendMessageResult#SUCCESS is defined in HAL as 0 */ assertEquals(0, callbackResult); assertTrue(handleResult); } @Test public void handleGiveDeviceVendorId_success() { mSrcAddr = ADDR_UNREGISTERED; mDesAddr = ADDR_BROADCAST; /** nativeGetVendorId returns 0 */ param = new byte[] { (byte) ((0 >> 8) & 0xFF), (byte) (0 & 0xFF), (byte) (0 & 0xFF) }; callbackResult = -1; mHdmiLocalDevice.handleGiveDeviceVendorId( (int finalResult) -> callbackResult = finalResult); mTestLooper.dispatchAll(); assertEquals(0, callbackResult); } }