Loading services/core/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -26,7 +26,6 @@ java_library_static { "services.net", "android.hardware.light-V2.0-java", "android.hardware.power-V1.0-java", "android.hardware.tv.cec-V1.0-java", "android.hardware.vibrator-java", "android.net.ipsec.ike.stubs.module_lib", "app-compat-annotations", Loading @@ -46,6 +45,7 @@ java_library_static { "android.hardware.health-V2.0-java", "android.hardware.health-V2.1-java", "android.hardware.light-java", "android.hardware.tv.cec-V1.0-java", "android.hardware.weaver-V1.0-java", "android.hardware.biometrics.face-V1.0-java", "android.hardware.biometrics.fingerprint-V2.1-java", Loading services/core/java/com/android/server/hdmi/HdmiCecController.java +209 −69 Original line number Diff line number Diff line Loading @@ -17,11 +17,18 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.tv.cec.V1_0.CecMessage; import android.hardware.tv.cec.V1_0.HotplugEvent; import android.hardware.tv.cec.V1_0.IHdmiCec; import android.hardware.tv.cec.V1_0.IHdmiCec.getPhysicalAddressCallback; import android.hardware.tv.cec.V1_0.IHdmiCecCallback; import android.hardware.tv.cec.V1_0.Result; import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.Handler; import android.os.IHwBinder; import android.os.Looper; import android.os.MessageQueue; import android.os.RemoteException; import android.util.Slog; import android.util.SparseArray; Loading Loading @@ -78,6 +85,11 @@ final class HdmiCecController { private static final int MAX_CEC_MESSAGE_HISTORY = 200; private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF; /** Cookie for matching the right end point. */ protected static final int HDMI_CEC_HAL_DEATH_COOKIE = 353; // Predicate for whether the given logical address is remote device's one or not. private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() { @Override Loading @@ -101,10 +113,6 @@ final class HdmiCecController { // device or issued by internal state change. private Handler mControlHandler; // Stores the pointer to the native implementation of the service that // interacts with HAL. private volatile long mNativePtr; private final HdmiControlService mService; // Stores the local CEC devices in the system. Device type is used for key. Loading Loading @@ -142,21 +150,19 @@ final class HdmiCecController { static HdmiCecController createWithNativeWrapper( HdmiControlService service, NativeWrapper nativeWrapper) { HdmiCecController controller = new HdmiCecController(service, nativeWrapper); long nativePtr = nativeWrapper .nativeInit(controller, service.getServiceLooper().getQueue()); if (nativePtr == 0L) { controller = null; String nativePtr = nativeWrapper.nativeInit(); if (nativePtr == null) { HdmiLogger.warning("Couldn't get tv.cec service."); return null; } controller.init(nativePtr); controller.init(nativeWrapper); return controller; } private void init(long nativePtr) { private void init(NativeWrapper nativeWrapper) { mIoHandler = new Handler(mService.getIoLooper()); mControlHandler = new Handler(mService.getServiceLooper()); mNativePtr = nativePtr; nativeWrapper.setCallback(new HdmiCecCallback()); } @ServiceThreadOnly Loading Loading @@ -251,7 +257,7 @@ final class HdmiCecController { HdmiPortInfo[] getPortInfos() { return mNativeWrapperImpl.nativeGetPortInfos(mNativePtr); return mNativeWrapperImpl.nativeGetPortInfos(); } /** Loading Loading @@ -279,7 +285,7 @@ final class HdmiCecController { int addLogicalAddress(int newLogicalAddress) { assertRunOnServiceThread(); if (HdmiUtils.isValidAddress(newLogicalAddress)) { return mNativeWrapperImpl.nativeAddLogicalAddress(mNativePtr, newLogicalAddress); return mNativeWrapperImpl.nativeAddLogicalAddress(newLogicalAddress); } else { return Result.FAILURE_INVALID_ARGS; } Loading @@ -296,7 +302,7 @@ final class HdmiCecController { for (int i = 0; i < mLocalDevices.size(); ++i) { mLocalDevices.valueAt(i).clearAddress(); } mNativeWrapperImpl.nativeClearLogicalAddress(mNativePtr); mNativeWrapperImpl.nativeClearLogicalAddress(); } @ServiceThreadOnly Loading @@ -316,7 +322,7 @@ final class HdmiCecController { @ServiceThreadOnly int getPhysicalAddress() { assertRunOnServiceThread(); return mNativeWrapperImpl.nativeGetPhysicalAddress(mNativePtr); return mNativeWrapperImpl.nativeGetPhysicalAddress(); } /** Loading @@ -327,7 +333,7 @@ final class HdmiCecController { @ServiceThreadOnly int getVersion() { assertRunOnServiceThread(); return mNativeWrapperImpl.nativeGetVersion(mNativePtr); return mNativeWrapperImpl.nativeGetVersion(); } /** Loading @@ -338,7 +344,7 @@ final class HdmiCecController { @ServiceThreadOnly int getVendorId() { assertRunOnServiceThread(); return mNativeWrapperImpl.nativeGetVendorId(mNativePtr); return mNativeWrapperImpl.nativeGetVendorId(); } /** Loading @@ -351,7 +357,7 @@ final class HdmiCecController { void setOption(int flag, boolean enabled) { assertRunOnServiceThread(); HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled); mNativeWrapperImpl.nativeSetOption(mNativePtr, flag, enabled); mNativeWrapperImpl.nativeSetOption(flag, enabled); } /** Loading @@ -365,7 +371,7 @@ final class HdmiCecController { if (!LanguageTag.isLanguage(language)) { return; } mNativeWrapperImpl.nativeSetLanguage(mNativePtr, language); mNativeWrapperImpl.nativeSetLanguage(language); } /** Loading @@ -377,7 +383,7 @@ final class HdmiCecController { @ServiceThreadOnly void enableAudioReturnChannel(int port, boolean enabled) { assertRunOnServiceThread(); mNativeWrapperImpl.nativeEnableAudioReturnChannel(mNativePtr, port, enabled); mNativeWrapperImpl.nativeEnableAudioReturnChannel(port, enabled); } /** Loading @@ -389,7 +395,7 @@ final class HdmiCecController { @ServiceThreadOnly boolean isConnected(int port) { assertRunOnServiceThread(); return mNativeWrapperImpl.nativeIsConnected(mNativePtr, port); return mNativeWrapperImpl.nativeIsConnected(port); } /** Loading Loading @@ -511,7 +517,7 @@ final class HdmiCecController { // <Polling Message> is a message which has empty body. int ret = mNativeWrapperImpl.nativeSendCecCommand( mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY); sourceAddress, destinationAddress, EMPTY_BODY); if (ret == SendMessageResult.SUCCESS) { return true; } else if (ret != SendMessageResult.NACK) { Loading Loading @@ -615,7 +621,7 @@ final class HdmiCecController { int i = 0; int errorCode = SendMessageResult.SUCCESS; do { errorCode = mNativeWrapperImpl.nativeSendCecCommand(mNativePtr, errorCode = mNativeWrapperImpl.nativeSendCecCommand( cecMessage.getSource(), cecMessage.getDestination(), body); if (errorCode == SendMessageResult.SUCCESS) { break; Loading @@ -639,7 +645,7 @@ final class HdmiCecController { } /** * Called by native when incoming CEC message arrived. * Called when incoming CEC message arrived. */ @ServiceThreadOnly private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) { Loading @@ -651,7 +657,7 @@ final class HdmiCecController { } /** * Called by native when a hotplug event issues. * Called when a hotplug event issues. */ @ServiceThreadOnly private void handleHotplug(int port, boolean connected) { Loading Loading @@ -687,18 +693,19 @@ final class HdmiCecController { } protected interface NativeWrapper { long nativeInit(HdmiCecController handler, MessageQueue messageQueue); int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body); int nativeAddLogicalAddress(long controllerPtr, int logicalAddress); void nativeClearLogicalAddress(long controllerPtr); int nativeGetPhysicalAddress(long controllerPtr); int nativeGetVersion(long controllerPtr); int nativeGetVendorId(long controllerPtr); HdmiPortInfo[] nativeGetPortInfos(long controllerPtr); void nativeSetOption(long controllerPtr, int flag, boolean enabled); void nativeSetLanguage(long controllerPtr, String language); void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag); boolean nativeIsConnected(long controllerPtr, int port); String nativeInit(); void setCallback(HdmiCecCallback callback); int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body); int nativeAddLogicalAddress(int logicalAddress); void nativeClearLogicalAddress(); int nativeGetPhysicalAddress(); int nativeGetVersion(); int nativeGetVendorId(); HdmiPortInfo[] nativeGetPortInfos(); void nativeSetOption(int flag, boolean enabled); void nativeSetLanguage(String language); void nativeEnableAudioReturnChannel(int port, boolean flag); boolean nativeIsConnected(int port); } private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue); Loading @@ -716,67 +723,200 @@ final class HdmiCecController { int port, boolean flag); private static native boolean nativeIsConnected(long controllerPtr, int port); private static final class NativeWrapperImpl implements NativeWrapper { private static final class NativeWrapperImpl implements NativeWrapper, IHwBinder.DeathRecipient, getPhysicalAddressCallback { private IHdmiCec mHdmiCec; private final Object mLock = new Object(); private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS; @Override public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) { return HdmiCecController.nativeInit(handler, messageQueue); public String nativeInit() { return (connectToHal() ? mHdmiCec.toString() : null); } boolean connectToHal() { try { mHdmiCec = IHdmiCec.getService(); try { mHdmiCec.linkToDeath(this, HDMI_CEC_HAL_DEATH_COOKIE); } catch (RemoteException e) { HdmiLogger.error("Couldn't link to death : ", e); } } catch (RemoteException e) { HdmiLogger.error("Couldn't get tv.cec service : ", e); return false; } return true; } @Override public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body) { return HdmiCecController.nativeSendCecCommand(controllerPtr, srcAddress, dstAddress, body); public void setCallback(HdmiCecCallback callback) { try { mHdmiCec.setCallback(callback); } catch (RemoteException e) { HdmiLogger.error("Couldn't initialise tv.cec callback : ", e); } } @Override public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) { return HdmiCecController.nativeAddLogicalAddress(controllerPtr, logicalAddress); public int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body) { CecMessage message = new CecMessage(); message.initiator = srcAddress; message.destination = dstAddress; message.body = new ArrayList<>(body.length); for (byte b : body) { message.body.add(b); } try { return mHdmiCec.sendMessage(message); } catch (RemoteException e) { HdmiLogger.error("Failed to send CEC message : ", e); return SendMessageResult.FAIL; } } @Override public void nativeClearLogicalAddress(long controllerPtr) { HdmiCecController.nativeClearLogicalAddress(controllerPtr); public int nativeAddLogicalAddress(int logicalAddress) { try { return mHdmiCec.addLogicalAddress(logicalAddress); } catch (RemoteException e) { HdmiLogger.error("Failed to add a logical address : ", e); return Result.FAILURE_INVALID_ARGS; } } @Override public int nativeGetPhysicalAddress(long controllerPtr) { return HdmiCecController.nativeGetPhysicalAddress(controllerPtr); public void nativeClearLogicalAddress() { try { mHdmiCec.clearLogicalAddress(); } catch (RemoteException e) { HdmiLogger.error("Failed to clear logical address : ", e); } } @Override public int nativeGetVersion(long controllerPtr) { return HdmiCecController.nativeGetVersion(controllerPtr); public int nativeGetPhysicalAddress() { try { mHdmiCec.getPhysicalAddress(this); return mPhysicalAddress; } catch (RemoteException e) { HdmiLogger.error("Failed to get physical address : ", e); return INVALID_PHYSICAL_ADDRESS; } } @Override public int nativeGetVendorId(long controllerPtr) { return HdmiCecController.nativeGetVendorId(controllerPtr); public int nativeGetVersion() { try { return mHdmiCec.getCecVersion(); } catch (RemoteException e) { HdmiLogger.error("Failed to get cec version : ", e); return Result.FAILURE_UNKNOWN; } } @Override public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) { return HdmiCecController.nativeGetPortInfos(controllerPtr); public int nativeGetVendorId() { try { return mHdmiCec.getVendorId(); } catch (RemoteException e) { HdmiLogger.error("Failed to get vendor id : ", e); return Result.FAILURE_UNKNOWN; } } @Override public void nativeSetOption(long controllerPtr, int flag, boolean enabled) { HdmiCecController.nativeSetOption(controllerPtr, flag, enabled); public HdmiPortInfo[] nativeGetPortInfos() { try { ArrayList<android.hardware.tv.cec.V1_0.HdmiPortInfo> hdmiPortInfos = mHdmiCec.getPortInfo(); HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.size()]; int i = 0; for (android.hardware.tv.cec.V1_0.HdmiPortInfo portInfo : hdmiPortInfos) { hdmiPortInfo[i] = new HdmiPortInfo(portInfo.portId, portInfo.type, portInfo.physicalAddress, portInfo.cecSupported, false, portInfo.arcSupported); i++; } return hdmiPortInfo; } catch (RemoteException e) { HdmiLogger.error("Failed to get port information : ", e); return null; } } @Override public void nativeSetLanguage(long controllerPtr, String language) { HdmiCecController.nativeSetLanguage(controllerPtr, language); public void nativeSetOption(int flag, boolean enabled) { try { mHdmiCec.setOption(flag, enabled); } catch (RemoteException e) { HdmiLogger.error("Failed to set option : ", e); } } @Override public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) { HdmiCecController.nativeEnableAudioReturnChannel(controllerPtr, port, flag); public void nativeSetLanguage(String language) { try { mHdmiCec.setLanguage(language); } catch (RemoteException e) { HdmiLogger.error("Failed to set language : ", e); } } @Override public void nativeEnableAudioReturnChannel(int port, boolean flag) { try { mHdmiCec.enableAudioReturnChannel(port, flag); } catch (RemoteException e) { HdmiLogger.error("Failed to enable/disable ARC : ", e); } } @Override public boolean nativeIsConnected(int port) { try { return mHdmiCec.isConnected(port); } catch (RemoteException e) { HdmiLogger.error("Failed to get connection info : ", e); return false; } } @Override public void serviceDied(long cookie) { if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) { HdmiLogger.error(TAG, "Service died cokkie : " + cookie + "; reconnecting"); connectToHal(); } } @Override public void onValues(int result, short addr) { if (result == Result.SUCCESS) { synchronized (mLock) { mPhysicalAddress = new Short(addr).intValue(); } } } } final class HdmiCecCallback extends IHdmiCecCallback.Stub { @Override public void onCecMessage(CecMessage message) throws RemoteException { byte[] body = new byte[message.body.size()]; for (int i = 0; i < message.body.size(); i++) { body[i] = message.body.get(i); } runOnServiceThread( () -> handleIncomingCecCommand(message.initiator, message.destination, body)); } @Override public boolean nativeIsConnected(long controllerPtr, int port) { return HdmiCecController.nativeIsConnected(controllerPtr, port); public void onHotplugEvent(HotplugEvent event) throws RemoteException { runOnServiceThread(() -> handleHotplug(event.portId, event.connected)); } } Loading services/core/java/com/android/server/hdmi/HdmiLogger.java +4 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,10 @@ final class HdmiLogger { getLogger().errorInternal(toLogString(logMessage, objs)); } static final void error(String logMessage, Exception e, Object... objs) { getLogger().errorInternal(toLogString(logMessage + e, objs)); } private void errorInternal(String logMessage) { String log = updateLog(mErrorTimingCache, logMessage); if (!log.isEmpty()) { Loading services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java +16 −14 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.MessageQueue; import com.android.internal.annotations.VisibleForTesting; import com.android.server.hdmi.HdmiCecController.NativeWrapper; Loading Loading @@ -53,13 +52,16 @@ final class FakeNativeWrapper implements NativeWrapper { private HdmiPortInfo[] mHdmiPortInfo = null; @Override public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) { return 1L; public String nativeInit() { return "[class or subclass of IHdmiCec]@Proxy"; } @Override public void setCallback(HdmiCecController.HdmiCecCallback callback) {} @Override public int nativeSendCecCommand( long controllerPtr, int srcAddress, int dstAddress, byte[] body) { int srcAddress, int dstAddress, byte[] body) { if (body.length == 0) { return mPollAddressResponse[dstAddress]; } else { Loading @@ -69,30 +71,30 @@ final class FakeNativeWrapper implements NativeWrapper { } @Override public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) { public int nativeAddLogicalAddress(int logicalAddress) { return 0; } @Override public void nativeClearLogicalAddress(long controllerPtr) {} public void nativeClearLogicalAddress() {} @Override public int nativeGetPhysicalAddress(long controllerPtr) { public int nativeGetPhysicalAddress() { return mMyPhysicalAddress; } @Override public int nativeGetVersion(long controllerPtr) { public int nativeGetVersion() { return 0; } @Override public int nativeGetVendorId(long controllerPtr) { public int nativeGetVendorId() { return 0; } @Override public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) { public HdmiPortInfo[] nativeGetPortInfos() { if (mHdmiPortInfo == null) { mHdmiPortInfo = new HdmiPortInfo[1]; mHdmiPortInfo[0] = new HdmiPortInfo(1, 1, 0x1000, true, true, true); Loading @@ -101,16 +103,16 @@ final class FakeNativeWrapper implements NativeWrapper { } @Override public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {} public void nativeSetOption(int flag, boolean enabled) {} @Override public void nativeSetLanguage(long controllerPtr, String language) {} public void nativeSetLanguage(String language) {} @Override public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {} public void nativeEnableAudioReturnChannel(int port, boolean flag) {} @Override public boolean nativeIsConnected(long controllerPtr, int port) { public boolean nativeIsConnected(int port) { return false; } Loading Loading
services/core/Android.bp +1 −1 Original line number Diff line number Diff line Loading @@ -26,7 +26,6 @@ java_library_static { "services.net", "android.hardware.light-V2.0-java", "android.hardware.power-V1.0-java", "android.hardware.tv.cec-V1.0-java", "android.hardware.vibrator-java", "android.net.ipsec.ike.stubs.module_lib", "app-compat-annotations", Loading @@ -46,6 +45,7 @@ java_library_static { "android.hardware.health-V2.0-java", "android.hardware.health-V2.1-java", "android.hardware.light-java", "android.hardware.tv.cec-V1.0-java", "android.hardware.weaver-V1.0-java", "android.hardware.biometrics.face-V1.0-java", "android.hardware.biometrics.fingerprint-V2.1-java", Loading
services/core/java/com/android/server/hdmi/HdmiCecController.java +209 −69 Original line number Diff line number Diff line Loading @@ -17,11 +17,18 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.tv.cec.V1_0.CecMessage; import android.hardware.tv.cec.V1_0.HotplugEvent; import android.hardware.tv.cec.V1_0.IHdmiCec; import android.hardware.tv.cec.V1_0.IHdmiCec.getPhysicalAddressCallback; import android.hardware.tv.cec.V1_0.IHdmiCecCallback; import android.hardware.tv.cec.V1_0.Result; import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.Handler; import android.os.IHwBinder; import android.os.Looper; import android.os.MessageQueue; import android.os.RemoteException; import android.util.Slog; import android.util.SparseArray; Loading Loading @@ -78,6 +85,11 @@ final class HdmiCecController { private static final int MAX_CEC_MESSAGE_HISTORY = 200; private static final int INVALID_PHYSICAL_ADDRESS = 0xFFFF; /** Cookie for matching the right end point. */ protected static final int HDMI_CEC_HAL_DEATH_COOKIE = 353; // Predicate for whether the given logical address is remote device's one or not. private final Predicate<Integer> mRemoteDeviceAddressPredicate = new Predicate<Integer>() { @Override Loading @@ -101,10 +113,6 @@ final class HdmiCecController { // device or issued by internal state change. private Handler mControlHandler; // Stores the pointer to the native implementation of the service that // interacts with HAL. private volatile long mNativePtr; private final HdmiControlService mService; // Stores the local CEC devices in the system. Device type is used for key. Loading Loading @@ -142,21 +150,19 @@ final class HdmiCecController { static HdmiCecController createWithNativeWrapper( HdmiControlService service, NativeWrapper nativeWrapper) { HdmiCecController controller = new HdmiCecController(service, nativeWrapper); long nativePtr = nativeWrapper .nativeInit(controller, service.getServiceLooper().getQueue()); if (nativePtr == 0L) { controller = null; String nativePtr = nativeWrapper.nativeInit(); if (nativePtr == null) { HdmiLogger.warning("Couldn't get tv.cec service."); return null; } controller.init(nativePtr); controller.init(nativeWrapper); return controller; } private void init(long nativePtr) { private void init(NativeWrapper nativeWrapper) { mIoHandler = new Handler(mService.getIoLooper()); mControlHandler = new Handler(mService.getServiceLooper()); mNativePtr = nativePtr; nativeWrapper.setCallback(new HdmiCecCallback()); } @ServiceThreadOnly Loading Loading @@ -251,7 +257,7 @@ final class HdmiCecController { HdmiPortInfo[] getPortInfos() { return mNativeWrapperImpl.nativeGetPortInfos(mNativePtr); return mNativeWrapperImpl.nativeGetPortInfos(); } /** Loading Loading @@ -279,7 +285,7 @@ final class HdmiCecController { int addLogicalAddress(int newLogicalAddress) { assertRunOnServiceThread(); if (HdmiUtils.isValidAddress(newLogicalAddress)) { return mNativeWrapperImpl.nativeAddLogicalAddress(mNativePtr, newLogicalAddress); return mNativeWrapperImpl.nativeAddLogicalAddress(newLogicalAddress); } else { return Result.FAILURE_INVALID_ARGS; } Loading @@ -296,7 +302,7 @@ final class HdmiCecController { for (int i = 0; i < mLocalDevices.size(); ++i) { mLocalDevices.valueAt(i).clearAddress(); } mNativeWrapperImpl.nativeClearLogicalAddress(mNativePtr); mNativeWrapperImpl.nativeClearLogicalAddress(); } @ServiceThreadOnly Loading @@ -316,7 +322,7 @@ final class HdmiCecController { @ServiceThreadOnly int getPhysicalAddress() { assertRunOnServiceThread(); return mNativeWrapperImpl.nativeGetPhysicalAddress(mNativePtr); return mNativeWrapperImpl.nativeGetPhysicalAddress(); } /** Loading @@ -327,7 +333,7 @@ final class HdmiCecController { @ServiceThreadOnly int getVersion() { assertRunOnServiceThread(); return mNativeWrapperImpl.nativeGetVersion(mNativePtr); return mNativeWrapperImpl.nativeGetVersion(); } /** Loading @@ -338,7 +344,7 @@ final class HdmiCecController { @ServiceThreadOnly int getVendorId() { assertRunOnServiceThread(); return mNativeWrapperImpl.nativeGetVendorId(mNativePtr); return mNativeWrapperImpl.nativeGetVendorId(); } /** Loading @@ -351,7 +357,7 @@ final class HdmiCecController { void setOption(int flag, boolean enabled) { assertRunOnServiceThread(); HdmiLogger.debug("setOption: [flag:%d, enabled:%b]", flag, enabled); mNativeWrapperImpl.nativeSetOption(mNativePtr, flag, enabled); mNativeWrapperImpl.nativeSetOption(flag, enabled); } /** Loading @@ -365,7 +371,7 @@ final class HdmiCecController { if (!LanguageTag.isLanguage(language)) { return; } mNativeWrapperImpl.nativeSetLanguage(mNativePtr, language); mNativeWrapperImpl.nativeSetLanguage(language); } /** Loading @@ -377,7 +383,7 @@ final class HdmiCecController { @ServiceThreadOnly void enableAudioReturnChannel(int port, boolean enabled) { assertRunOnServiceThread(); mNativeWrapperImpl.nativeEnableAudioReturnChannel(mNativePtr, port, enabled); mNativeWrapperImpl.nativeEnableAudioReturnChannel(port, enabled); } /** Loading @@ -389,7 +395,7 @@ final class HdmiCecController { @ServiceThreadOnly boolean isConnected(int port) { assertRunOnServiceThread(); return mNativeWrapperImpl.nativeIsConnected(mNativePtr, port); return mNativeWrapperImpl.nativeIsConnected(port); } /** Loading Loading @@ -511,7 +517,7 @@ final class HdmiCecController { // <Polling Message> is a message which has empty body. int ret = mNativeWrapperImpl.nativeSendCecCommand( mNativePtr, sourceAddress, destinationAddress, EMPTY_BODY); sourceAddress, destinationAddress, EMPTY_BODY); if (ret == SendMessageResult.SUCCESS) { return true; } else if (ret != SendMessageResult.NACK) { Loading Loading @@ -615,7 +621,7 @@ final class HdmiCecController { int i = 0; int errorCode = SendMessageResult.SUCCESS; do { errorCode = mNativeWrapperImpl.nativeSendCecCommand(mNativePtr, errorCode = mNativeWrapperImpl.nativeSendCecCommand( cecMessage.getSource(), cecMessage.getDestination(), body); if (errorCode == SendMessageResult.SUCCESS) { break; Loading @@ -639,7 +645,7 @@ final class HdmiCecController { } /** * Called by native when incoming CEC message arrived. * Called when incoming CEC message arrived. */ @ServiceThreadOnly private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) { Loading @@ -651,7 +657,7 @@ final class HdmiCecController { } /** * Called by native when a hotplug event issues. * Called when a hotplug event issues. */ @ServiceThreadOnly private void handleHotplug(int port, boolean connected) { Loading Loading @@ -687,18 +693,19 @@ final class HdmiCecController { } protected interface NativeWrapper { long nativeInit(HdmiCecController handler, MessageQueue messageQueue); int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body); int nativeAddLogicalAddress(long controllerPtr, int logicalAddress); void nativeClearLogicalAddress(long controllerPtr); int nativeGetPhysicalAddress(long controllerPtr); int nativeGetVersion(long controllerPtr); int nativeGetVendorId(long controllerPtr); HdmiPortInfo[] nativeGetPortInfos(long controllerPtr); void nativeSetOption(long controllerPtr, int flag, boolean enabled); void nativeSetLanguage(long controllerPtr, String language); void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag); boolean nativeIsConnected(long controllerPtr, int port); String nativeInit(); void setCallback(HdmiCecCallback callback); int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body); int nativeAddLogicalAddress(int logicalAddress); void nativeClearLogicalAddress(); int nativeGetPhysicalAddress(); int nativeGetVersion(); int nativeGetVendorId(); HdmiPortInfo[] nativeGetPortInfos(); void nativeSetOption(int flag, boolean enabled); void nativeSetLanguage(String language); void nativeEnableAudioReturnChannel(int port, boolean flag); boolean nativeIsConnected(int port); } private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue); Loading @@ -716,67 +723,200 @@ final class HdmiCecController { int port, boolean flag); private static native boolean nativeIsConnected(long controllerPtr, int port); private static final class NativeWrapperImpl implements NativeWrapper { private static final class NativeWrapperImpl implements NativeWrapper, IHwBinder.DeathRecipient, getPhysicalAddressCallback { private IHdmiCec mHdmiCec; private final Object mLock = new Object(); private int mPhysicalAddress = INVALID_PHYSICAL_ADDRESS; @Override public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) { return HdmiCecController.nativeInit(handler, messageQueue); public String nativeInit() { return (connectToHal() ? mHdmiCec.toString() : null); } boolean connectToHal() { try { mHdmiCec = IHdmiCec.getService(); try { mHdmiCec.linkToDeath(this, HDMI_CEC_HAL_DEATH_COOKIE); } catch (RemoteException e) { HdmiLogger.error("Couldn't link to death : ", e); } } catch (RemoteException e) { HdmiLogger.error("Couldn't get tv.cec service : ", e); return false; } return true; } @Override public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body) { return HdmiCecController.nativeSendCecCommand(controllerPtr, srcAddress, dstAddress, body); public void setCallback(HdmiCecCallback callback) { try { mHdmiCec.setCallback(callback); } catch (RemoteException e) { HdmiLogger.error("Couldn't initialise tv.cec callback : ", e); } } @Override public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) { return HdmiCecController.nativeAddLogicalAddress(controllerPtr, logicalAddress); public int nativeSendCecCommand(int srcAddress, int dstAddress, byte[] body) { CecMessage message = new CecMessage(); message.initiator = srcAddress; message.destination = dstAddress; message.body = new ArrayList<>(body.length); for (byte b : body) { message.body.add(b); } try { return mHdmiCec.sendMessage(message); } catch (RemoteException e) { HdmiLogger.error("Failed to send CEC message : ", e); return SendMessageResult.FAIL; } } @Override public void nativeClearLogicalAddress(long controllerPtr) { HdmiCecController.nativeClearLogicalAddress(controllerPtr); public int nativeAddLogicalAddress(int logicalAddress) { try { return mHdmiCec.addLogicalAddress(logicalAddress); } catch (RemoteException e) { HdmiLogger.error("Failed to add a logical address : ", e); return Result.FAILURE_INVALID_ARGS; } } @Override public int nativeGetPhysicalAddress(long controllerPtr) { return HdmiCecController.nativeGetPhysicalAddress(controllerPtr); public void nativeClearLogicalAddress() { try { mHdmiCec.clearLogicalAddress(); } catch (RemoteException e) { HdmiLogger.error("Failed to clear logical address : ", e); } } @Override public int nativeGetVersion(long controllerPtr) { return HdmiCecController.nativeGetVersion(controllerPtr); public int nativeGetPhysicalAddress() { try { mHdmiCec.getPhysicalAddress(this); return mPhysicalAddress; } catch (RemoteException e) { HdmiLogger.error("Failed to get physical address : ", e); return INVALID_PHYSICAL_ADDRESS; } } @Override public int nativeGetVendorId(long controllerPtr) { return HdmiCecController.nativeGetVendorId(controllerPtr); public int nativeGetVersion() { try { return mHdmiCec.getCecVersion(); } catch (RemoteException e) { HdmiLogger.error("Failed to get cec version : ", e); return Result.FAILURE_UNKNOWN; } } @Override public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) { return HdmiCecController.nativeGetPortInfos(controllerPtr); public int nativeGetVendorId() { try { return mHdmiCec.getVendorId(); } catch (RemoteException e) { HdmiLogger.error("Failed to get vendor id : ", e); return Result.FAILURE_UNKNOWN; } } @Override public void nativeSetOption(long controllerPtr, int flag, boolean enabled) { HdmiCecController.nativeSetOption(controllerPtr, flag, enabled); public HdmiPortInfo[] nativeGetPortInfos() { try { ArrayList<android.hardware.tv.cec.V1_0.HdmiPortInfo> hdmiPortInfos = mHdmiCec.getPortInfo(); HdmiPortInfo[] hdmiPortInfo = new HdmiPortInfo[hdmiPortInfos.size()]; int i = 0; for (android.hardware.tv.cec.V1_0.HdmiPortInfo portInfo : hdmiPortInfos) { hdmiPortInfo[i] = new HdmiPortInfo(portInfo.portId, portInfo.type, portInfo.physicalAddress, portInfo.cecSupported, false, portInfo.arcSupported); i++; } return hdmiPortInfo; } catch (RemoteException e) { HdmiLogger.error("Failed to get port information : ", e); return null; } } @Override public void nativeSetLanguage(long controllerPtr, String language) { HdmiCecController.nativeSetLanguage(controllerPtr, language); public void nativeSetOption(int flag, boolean enabled) { try { mHdmiCec.setOption(flag, enabled); } catch (RemoteException e) { HdmiLogger.error("Failed to set option : ", e); } } @Override public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) { HdmiCecController.nativeEnableAudioReturnChannel(controllerPtr, port, flag); public void nativeSetLanguage(String language) { try { mHdmiCec.setLanguage(language); } catch (RemoteException e) { HdmiLogger.error("Failed to set language : ", e); } } @Override public void nativeEnableAudioReturnChannel(int port, boolean flag) { try { mHdmiCec.enableAudioReturnChannel(port, flag); } catch (RemoteException e) { HdmiLogger.error("Failed to enable/disable ARC : ", e); } } @Override public boolean nativeIsConnected(int port) { try { return mHdmiCec.isConnected(port); } catch (RemoteException e) { HdmiLogger.error("Failed to get connection info : ", e); return false; } } @Override public void serviceDied(long cookie) { if (cookie == HDMI_CEC_HAL_DEATH_COOKIE) { HdmiLogger.error(TAG, "Service died cokkie : " + cookie + "; reconnecting"); connectToHal(); } } @Override public void onValues(int result, short addr) { if (result == Result.SUCCESS) { synchronized (mLock) { mPhysicalAddress = new Short(addr).intValue(); } } } } final class HdmiCecCallback extends IHdmiCecCallback.Stub { @Override public void onCecMessage(CecMessage message) throws RemoteException { byte[] body = new byte[message.body.size()]; for (int i = 0; i < message.body.size(); i++) { body[i] = message.body.get(i); } runOnServiceThread( () -> handleIncomingCecCommand(message.initiator, message.destination, body)); } @Override public boolean nativeIsConnected(long controllerPtr, int port) { return HdmiCecController.nativeIsConnected(controllerPtr, port); public void onHotplugEvent(HotplugEvent event) throws RemoteException { runOnServiceThread(() -> handleHotplug(event.portId, event.connected)); } } Loading
services/core/java/com/android/server/hdmi/HdmiLogger.java +4 −0 Original line number Diff line number Diff line Loading @@ -71,6 +71,10 @@ final class HdmiLogger { getLogger().errorInternal(toLogString(logMessage, objs)); } static final void error(String logMessage, Exception e, Object... objs) { getLogger().errorInternal(toLogString(logMessage + e, objs)); } private void errorInternal(String logMessage) { String log = updateLog(mErrorTimingCache, logMessage); if (!log.isEmpty()) { Loading
services/tests/servicestests/src/com/android/server/hdmi/FakeNativeWrapper.java +16 −14 Original line number Diff line number Diff line Loading @@ -17,7 +17,6 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiPortInfo; import android.hardware.tv.cec.V1_0.SendMessageResult; import android.os.MessageQueue; import com.android.internal.annotations.VisibleForTesting; import com.android.server.hdmi.HdmiCecController.NativeWrapper; Loading Loading @@ -53,13 +52,16 @@ final class FakeNativeWrapper implements NativeWrapper { private HdmiPortInfo[] mHdmiPortInfo = null; @Override public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) { return 1L; public String nativeInit() { return "[class or subclass of IHdmiCec]@Proxy"; } @Override public void setCallback(HdmiCecController.HdmiCecCallback callback) {} @Override public int nativeSendCecCommand( long controllerPtr, int srcAddress, int dstAddress, byte[] body) { int srcAddress, int dstAddress, byte[] body) { if (body.length == 0) { return mPollAddressResponse[dstAddress]; } else { Loading @@ -69,30 +71,30 @@ final class FakeNativeWrapper implements NativeWrapper { } @Override public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) { public int nativeAddLogicalAddress(int logicalAddress) { return 0; } @Override public void nativeClearLogicalAddress(long controllerPtr) {} public void nativeClearLogicalAddress() {} @Override public int nativeGetPhysicalAddress(long controllerPtr) { public int nativeGetPhysicalAddress() { return mMyPhysicalAddress; } @Override public int nativeGetVersion(long controllerPtr) { public int nativeGetVersion() { return 0; } @Override public int nativeGetVendorId(long controllerPtr) { public int nativeGetVendorId() { return 0; } @Override public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) { public HdmiPortInfo[] nativeGetPortInfos() { if (mHdmiPortInfo == null) { mHdmiPortInfo = new HdmiPortInfo[1]; mHdmiPortInfo[0] = new HdmiPortInfo(1, 1, 0x1000, true, true, true); Loading @@ -101,16 +103,16 @@ final class FakeNativeWrapper implements NativeWrapper { } @Override public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {} public void nativeSetOption(int flag, boolean enabled) {} @Override public void nativeSetLanguage(long controllerPtr, String language) {} public void nativeSetLanguage(String language) {} @Override public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {} public void nativeEnableAudioReturnChannel(int port, boolean flag) {} @Override public boolean nativeIsConnected(long controllerPtr, int port) { public boolean nativeIsConnected(int port) { return false; } Loading