Loading services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java 0 → 100644 +192 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 android.stats.hdmi.HdmiStatsEnums; import com.android.internal.util.FrameworkStatsLog; class HdmiCecAtomWriter { private static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100; private static final int ERROR_CODE_UNKNOWN = -1; /** * Writes a HdmiCecMessageReported atom representing an HDMI CEC message. * Should only be directly used for sent messages; for received messages, * use the overloaded version with the errorCode argument omitted. * * @param message The HDMI CEC message * @param direction Whether the message is incoming, outgoing, or neither * @param errorCode The error code from the final attempt to send the message */ public void messageReported(HdmiCecMessage message, int direction, int errorCode) { MessageReportedGenericArgs genericArgs = createMessageReportedGenericArgs( message, direction, errorCode); MessageReportedSpecialArgs specialArgs = createMessageReportedSpecialArgs(message); messageReportedBase(genericArgs, specialArgs); } /** * Version of messageReported for received messages, where no error code is present. * * @param message The HDMI CEC message * @param direction Whether the message is incoming, outgoing, or neither */ public void messageReported(HdmiCecMessage message, int direction) { messageReported(message, direction, ERROR_CODE_UNKNOWN); } /** * Constructs the generic arguments for logging a HDMI CEC message. * * @param message The HDMI CEC message * @param direction Whether the message is incoming, outgoing, or neither * @param errorCode The error code of the message if it's outgoing; * otherwise, ERROR_CODE_UNKNOWN */ private MessageReportedGenericArgs createMessageReportedGenericArgs( HdmiCecMessage message, int direction, int errorCode) { int sendMessageResult = errorCode == ERROR_CODE_UNKNOWN ? HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN : errorCode + 10; return new MessageReportedGenericArgs(direction, message.getSource(), message.getDestination(), message.getOpcode(), sendMessageResult); } /** * Constructs the special arguments for logging an HDMI CEC message. * * @param message The HDMI CEC message to log * @return An object containing the special arguments for the message */ private MessageReportedSpecialArgs createMessageReportedSpecialArgs(HdmiCecMessage message) { // Special arguments depend on message opcode switch (message.getOpcode()) { case Constants.MESSAGE_USER_CONTROL_PRESSED: return createUserControlPressedSpecialArgs(message); case Constants.MESSAGE_FEATURE_ABORT: return createFeatureAbortSpecialArgs(message); default: return new MessageReportedSpecialArgs(); } } /** * Constructs the special arguments for a <User Control Pressed> message. * * @param message The HDMI CEC message to log */ private MessageReportedSpecialArgs createUserControlPressedSpecialArgs( HdmiCecMessage message) { MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs(); int keycode = message.getParams()[0]; if (keycode >= 0x1E && keycode <= 0x29) { specialArgs.mUserControlPressedCommand = HdmiStatsEnums.NUMBER; } else { specialArgs.mUserControlPressedCommand = keycode + 0x100; } return specialArgs; } /** * Constructs method for constructing the special arguments for a <Feature Abort> message. * * @param message The HDMI CEC message to log */ private MessageReportedSpecialArgs createFeatureAbortSpecialArgs(HdmiCecMessage message) { MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs(); specialArgs.mFeatureAbortOpcode = message.getParams()[0] & 0xFF; // Unsigned byte specialArgs.mFeatureAbortReason = message.getParams()[1] + 10; return specialArgs; } /** * Writes a HdmiCecMessageReported atom. * * @param genericArgs Generic arguments; shared by all HdmiCecMessageReported atoms * @param specialArgs Special arguments; depends on the opcode of the message */ private void messageReportedBase(MessageReportedGenericArgs genericArgs, MessageReportedSpecialArgs specialArgs) { FrameworkStatsLog.write( FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED, 0, // Placeholder field genericArgs.mDirection, genericArgs.mInitiatorLogicalAddress, genericArgs.mDestinationLogicalAddress, genericArgs.mOpcode, genericArgs.mSendMessageResult, specialArgs.mUserControlPressedCommand, specialArgs.mFeatureAbortOpcode, specialArgs.mFeatureAbortReason); } /** * Writes a HdmiCecActiveSourceChanged atom representing a change in the active source. * * @param logicalAddress The Logical Address of the new active source * @param physicalAddress The Physical Address of the new active source * @param relationshipToActiveSource The relationship between this device and the active source */ public void activeSourceChanged(int logicalAddress, int physicalAddress, @Constants.PathRelationship int relationshipToActiveSource) { FrameworkStatsLog.write( FrameworkStatsLog.HDMI_CEC_ACTIVE_SOURCE_CHANGED, logicalAddress, physicalAddress, relationshipToActiveSource ); } /** * Contains the required arguments for creating any HdmiCecMessageReported atom */ private class MessageReportedGenericArgs { final int mDirection; final int mInitiatorLogicalAddress; final int mDestinationLogicalAddress; final int mOpcode; final int mSendMessageResult; MessageReportedGenericArgs(int direction, int initiatorLogicalAddress, int destinationLogicalAddress, int opcode, int sendMessageResult) { this.mDirection = direction; this.mInitiatorLogicalAddress = initiatorLogicalAddress; this.mDestinationLogicalAddress = destinationLogicalAddress; this.mOpcode = opcode; this.mSendMessageResult = sendMessageResult; } } /** * Contains the opcode-dependent arguments for creating a HdmiCecMessageReported atom. Each * field is initialized to a null-like value by default. Therefore, a freshly constructed * instance of this object represents a HDMI CEC message whose type does not require any * additional arguments. */ private class MessageReportedSpecialArgs { int mUserControlPressedCommand = HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN; int mFeatureAbortOpcode = FEATURE_ABORT_OPCODE_UNKNOWN; int mFeatureAbortReason = HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN; } } services/core/java/com/android/server/hdmi/HdmiCecController.java +56 −15 Original line number Diff line number Diff line Loading @@ -28,9 +28,11 @@ import android.os.Handler; import android.os.IHwBinder; import android.os.Looper; import android.os.RemoteException; import android.stats.hdmi.HdmiStatsEnums; import android.util.Slog; import android.util.SparseArray; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; Loading Loading @@ -123,10 +125,14 @@ final class HdmiCecController { private final NativeWrapper mNativeWrapperImpl; private final HdmiCecAtomWriter mHdmiCecAtomWriter; // Private constructor. Use HdmiCecController.create(). private HdmiCecController(HdmiControlService service, NativeWrapper nativeWrapper) { private HdmiCecController( HdmiControlService service, NativeWrapper nativeWrapper, HdmiCecAtomWriter atomWriter) { mService = service; mNativeWrapperImpl = nativeWrapper; mHdmiCecAtomWriter = atomWriter; } /** Loading @@ -136,19 +142,20 @@ final class HdmiCecController { * <p>Declared as package-private, accessed by {@link HdmiControlService} only. * @param service {@link HdmiControlService} instance used to create internal handler * and to pass callback for incoming message or event. * @param atomWriter {@link HdmiCecAtomWriter} instance for writing atoms for metrics. * @return {@link HdmiCecController} if device is initialized successfully. Otherwise, * returns {@code null}. */ static HdmiCecController create(HdmiControlService service) { return createWithNativeWrapper(service, new NativeWrapperImpl()); static HdmiCecController create(HdmiControlService service, HdmiCecAtomWriter atomWriter) { return createWithNativeWrapper(service, new NativeWrapperImpl(), atomWriter); } /** * A factory method with injection of native methods for testing. */ static HdmiCecController createWithNativeWrapper( HdmiControlService service, NativeWrapper nativeWrapper) { HdmiCecController controller = new HdmiCecController(service, nativeWrapper); HdmiControlService service, NativeWrapper nativeWrapper, HdmiCecAtomWriter atomWriter) { HdmiCecController controller = new HdmiCecController(service, nativeWrapper, atomWriter); String nativePtr = nativeWrapper.nativeInit(); if (nativePtr == null) { HdmiLogger.warning("Couldn't get tv.cec service."); Loading Loading @@ -619,7 +626,7 @@ final class HdmiCecController { public void run() { HdmiLogger.debug("[S]:" + cecMessage); byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams()); int i = 0; int retransmissionCount = 0; int errorCode = SendMessageResult.SUCCESS; do { errorCode = mNativeWrapperImpl.nativeSendCecCommand( Loading @@ -627,20 +634,25 @@ final class HdmiCecController { if (errorCode == SendMessageResult.SUCCESS) { break; } } while (i++ < HdmiConfig.RETRANSMISSION_COUNT); } while (retransmissionCount++ < HdmiConfig.RETRANSMISSION_COUNT); final int finalError = errorCode; if (finalError != SendMessageResult.SUCCESS) { Slog.w(TAG, "Failed to send " + cecMessage + " with errorCode=" + finalError); } if (callback != null) { runOnServiceThread(new Runnable() { @Override public void run() { mHdmiCecAtomWriter.messageReported( cecMessage, FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED__DIRECTION__OUTGOING, finalError ); if (callback != null) { callback.onSendCompleted(finalError); } }); } }); } }); } Loading @@ -654,9 +666,38 @@ final class HdmiCecController { HdmiCecMessage command = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body); HdmiLogger.debug("[R]:" + command); addCecMessageToHistory(true /* isReceived */, command); mHdmiCecAtomWriter.messageReported(command, incomingMessageDirection(srcAddress, dstAddress)); onReceiveCommand(command); } /** * Computes the direction of an incoming message, as implied by the source and * destination addresses. This will usually return INCOMING; if not, it can indicate a bug. */ private int incomingMessageDirection(int srcAddress, int dstAddress) { boolean sourceIsLocal = false; boolean destinationIsLocal = false; for (HdmiCecLocalDevice localDevice : getLocalDeviceList()) { int logicalAddress = localDevice.getDeviceInfo().getLogicalAddress(); if (logicalAddress == srcAddress) { sourceIsLocal = true; } if (logicalAddress == dstAddress) { destinationIsLocal = true; } } if (!sourceIsLocal && destinationIsLocal) { return HdmiStatsEnums.INCOMING; } else if (sourceIsLocal && destinationIsLocal) { return HdmiStatsEnums.TO_SELF; } return HdmiStatsEnums.MESSAGE_DIRECTION_OTHER; } /** * Called when a hotplug event issues. */ Loading services/core/java/com/android/server/hdmi/HdmiControlService.java +14 −1 Original line number Diff line number Diff line Loading @@ -397,6 +397,10 @@ public class HdmiControlService extends SystemService { // Set to true if the logical address allocation is completed. private boolean mAddressAllocated = false; // Object that handles logging statsd atoms. // Use getAtomWriter() instead of accessing directly, to allow dependency injection for testing. private HdmiCecAtomWriter mAtomWriter = new HdmiCecAtomWriter(); // Buffer for processing the incoming cec messages while allocating logical addresses. private final class CecMessageBuffer { private List<HdmiCecMessage> mBuffer = new ArrayList<>(); Loading Loading @@ -509,7 +513,7 @@ public class HdmiControlService extends SystemService { mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); if (mCecController == null) { mCecController = HdmiCecController.create(this); mCecController = HdmiCecController.create(this, getAtomWriter()); } if (mCecController != null) { if (mHdmiControlEnabled) { Loading Loading @@ -3233,6 +3237,10 @@ public class HdmiControlService extends SystemService { mActiveSource.logicalAddress = logicalAddress; mActiveSource.physicalAddress = physicalAddress; } getAtomWriter().activeSourceChanged(logicalAddress, physicalAddress, HdmiUtils.pathRelationship(getPhysicalAddress(), physicalAddress)); // If the current device is a source device, check if the current Active Source matches // the local device info. Set mIsActiveSource of the local device accordingly. for (HdmiCecLocalDevice device : getAllLocalDevices()) { Loading Loading @@ -3363,6 +3371,11 @@ public class HdmiControlService extends SystemService { } } @VisibleForTesting HdmiCecAtomWriter getAtomWriter() { return mAtomWriter; } boolean isMhlInputChangeEnabled() { synchronized (mLock) { return mMhlInputChangeEnabled; Loading services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -110,7 +110,7 @@ public class ActiveSourceActionTest { mHdmiControlService.setIoLooper(looper); mNativeWrapper = new FakeNativeWrapper(); HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( this.mHdmiControlService, mNativeWrapper); this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); mHdmiControlService.setCecController(hdmiCecController); mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); Loading services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java +2 −2 Original line number Diff line number Diff line Loading @@ -137,8 +137,8 @@ public class ArcInitiationActionFromAvrTest { Looper looper = mTestLooper.getLooper(); mHdmiControlService.setIoLooper(looper); mNativeWrapper = new FakeNativeWrapper(); mHdmiCecController = HdmiCecController.createWithNativeWrapper(this.mHdmiControlService, mNativeWrapper); mHdmiCecController = HdmiCecController.createWithNativeWrapper( this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); mHdmiControlService.setCecController(mHdmiCecController); mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); Loading Loading
services/core/java/com/android/server/hdmi/HdmiCecAtomWriter.java 0 → 100644 +192 −0 Original line number Diff line number Diff line /* * Copyright (C) 2020 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 android.stats.hdmi.HdmiStatsEnums; import com.android.internal.util.FrameworkStatsLog; class HdmiCecAtomWriter { private static final int FEATURE_ABORT_OPCODE_UNKNOWN = 0x100; private static final int ERROR_CODE_UNKNOWN = -1; /** * Writes a HdmiCecMessageReported atom representing an HDMI CEC message. * Should only be directly used for sent messages; for received messages, * use the overloaded version with the errorCode argument omitted. * * @param message The HDMI CEC message * @param direction Whether the message is incoming, outgoing, or neither * @param errorCode The error code from the final attempt to send the message */ public void messageReported(HdmiCecMessage message, int direction, int errorCode) { MessageReportedGenericArgs genericArgs = createMessageReportedGenericArgs( message, direction, errorCode); MessageReportedSpecialArgs specialArgs = createMessageReportedSpecialArgs(message); messageReportedBase(genericArgs, specialArgs); } /** * Version of messageReported for received messages, where no error code is present. * * @param message The HDMI CEC message * @param direction Whether the message is incoming, outgoing, or neither */ public void messageReported(HdmiCecMessage message, int direction) { messageReported(message, direction, ERROR_CODE_UNKNOWN); } /** * Constructs the generic arguments for logging a HDMI CEC message. * * @param message The HDMI CEC message * @param direction Whether the message is incoming, outgoing, or neither * @param errorCode The error code of the message if it's outgoing; * otherwise, ERROR_CODE_UNKNOWN */ private MessageReportedGenericArgs createMessageReportedGenericArgs( HdmiCecMessage message, int direction, int errorCode) { int sendMessageResult = errorCode == ERROR_CODE_UNKNOWN ? HdmiStatsEnums.SEND_MESSAGE_RESULT_UNKNOWN : errorCode + 10; return new MessageReportedGenericArgs(direction, message.getSource(), message.getDestination(), message.getOpcode(), sendMessageResult); } /** * Constructs the special arguments for logging an HDMI CEC message. * * @param message The HDMI CEC message to log * @return An object containing the special arguments for the message */ private MessageReportedSpecialArgs createMessageReportedSpecialArgs(HdmiCecMessage message) { // Special arguments depend on message opcode switch (message.getOpcode()) { case Constants.MESSAGE_USER_CONTROL_PRESSED: return createUserControlPressedSpecialArgs(message); case Constants.MESSAGE_FEATURE_ABORT: return createFeatureAbortSpecialArgs(message); default: return new MessageReportedSpecialArgs(); } } /** * Constructs the special arguments for a <User Control Pressed> message. * * @param message The HDMI CEC message to log */ private MessageReportedSpecialArgs createUserControlPressedSpecialArgs( HdmiCecMessage message) { MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs(); int keycode = message.getParams()[0]; if (keycode >= 0x1E && keycode <= 0x29) { specialArgs.mUserControlPressedCommand = HdmiStatsEnums.NUMBER; } else { specialArgs.mUserControlPressedCommand = keycode + 0x100; } return specialArgs; } /** * Constructs method for constructing the special arguments for a <Feature Abort> message. * * @param message The HDMI CEC message to log */ private MessageReportedSpecialArgs createFeatureAbortSpecialArgs(HdmiCecMessage message) { MessageReportedSpecialArgs specialArgs = new MessageReportedSpecialArgs(); specialArgs.mFeatureAbortOpcode = message.getParams()[0] & 0xFF; // Unsigned byte specialArgs.mFeatureAbortReason = message.getParams()[1] + 10; return specialArgs; } /** * Writes a HdmiCecMessageReported atom. * * @param genericArgs Generic arguments; shared by all HdmiCecMessageReported atoms * @param specialArgs Special arguments; depends on the opcode of the message */ private void messageReportedBase(MessageReportedGenericArgs genericArgs, MessageReportedSpecialArgs specialArgs) { FrameworkStatsLog.write( FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED, 0, // Placeholder field genericArgs.mDirection, genericArgs.mInitiatorLogicalAddress, genericArgs.mDestinationLogicalAddress, genericArgs.mOpcode, genericArgs.mSendMessageResult, specialArgs.mUserControlPressedCommand, specialArgs.mFeatureAbortOpcode, specialArgs.mFeatureAbortReason); } /** * Writes a HdmiCecActiveSourceChanged atom representing a change in the active source. * * @param logicalAddress The Logical Address of the new active source * @param physicalAddress The Physical Address of the new active source * @param relationshipToActiveSource The relationship between this device and the active source */ public void activeSourceChanged(int logicalAddress, int physicalAddress, @Constants.PathRelationship int relationshipToActiveSource) { FrameworkStatsLog.write( FrameworkStatsLog.HDMI_CEC_ACTIVE_SOURCE_CHANGED, logicalAddress, physicalAddress, relationshipToActiveSource ); } /** * Contains the required arguments for creating any HdmiCecMessageReported atom */ private class MessageReportedGenericArgs { final int mDirection; final int mInitiatorLogicalAddress; final int mDestinationLogicalAddress; final int mOpcode; final int mSendMessageResult; MessageReportedGenericArgs(int direction, int initiatorLogicalAddress, int destinationLogicalAddress, int opcode, int sendMessageResult) { this.mDirection = direction; this.mInitiatorLogicalAddress = initiatorLogicalAddress; this.mDestinationLogicalAddress = destinationLogicalAddress; this.mOpcode = opcode; this.mSendMessageResult = sendMessageResult; } } /** * Contains the opcode-dependent arguments for creating a HdmiCecMessageReported atom. Each * field is initialized to a null-like value by default. Therefore, a freshly constructed * instance of this object represents a HDMI CEC message whose type does not require any * additional arguments. */ private class MessageReportedSpecialArgs { int mUserControlPressedCommand = HdmiStatsEnums.USER_CONTROL_PRESSED_COMMAND_UNKNOWN; int mFeatureAbortOpcode = FEATURE_ABORT_OPCODE_UNKNOWN; int mFeatureAbortReason = HdmiStatsEnums.FEATURE_ABORT_REASON_UNKNOWN; } }
services/core/java/com/android/server/hdmi/HdmiCecController.java +56 −15 Original line number Diff line number Diff line Loading @@ -28,9 +28,11 @@ import android.os.Handler; import android.os.IHwBinder; import android.os.Looper; import android.os.RemoteException; import android.stats.hdmi.HdmiStatsEnums; import android.util.Slog; import android.util.SparseArray; import com.android.internal.util.FrameworkStatsLog; import com.android.internal.util.IndentingPrintWriter; import com.android.server.hdmi.HdmiAnnotations.IoThreadOnly; import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly; Loading Loading @@ -123,10 +125,14 @@ final class HdmiCecController { private final NativeWrapper mNativeWrapperImpl; private final HdmiCecAtomWriter mHdmiCecAtomWriter; // Private constructor. Use HdmiCecController.create(). private HdmiCecController(HdmiControlService service, NativeWrapper nativeWrapper) { private HdmiCecController( HdmiControlService service, NativeWrapper nativeWrapper, HdmiCecAtomWriter atomWriter) { mService = service; mNativeWrapperImpl = nativeWrapper; mHdmiCecAtomWriter = atomWriter; } /** Loading @@ -136,19 +142,20 @@ final class HdmiCecController { * <p>Declared as package-private, accessed by {@link HdmiControlService} only. * @param service {@link HdmiControlService} instance used to create internal handler * and to pass callback for incoming message or event. * @param atomWriter {@link HdmiCecAtomWriter} instance for writing atoms for metrics. * @return {@link HdmiCecController} if device is initialized successfully. Otherwise, * returns {@code null}. */ static HdmiCecController create(HdmiControlService service) { return createWithNativeWrapper(service, new NativeWrapperImpl()); static HdmiCecController create(HdmiControlService service, HdmiCecAtomWriter atomWriter) { return createWithNativeWrapper(service, new NativeWrapperImpl(), atomWriter); } /** * A factory method with injection of native methods for testing. */ static HdmiCecController createWithNativeWrapper( HdmiControlService service, NativeWrapper nativeWrapper) { HdmiCecController controller = new HdmiCecController(service, nativeWrapper); HdmiControlService service, NativeWrapper nativeWrapper, HdmiCecAtomWriter atomWriter) { HdmiCecController controller = new HdmiCecController(service, nativeWrapper, atomWriter); String nativePtr = nativeWrapper.nativeInit(); if (nativePtr == null) { HdmiLogger.warning("Couldn't get tv.cec service."); Loading Loading @@ -619,7 +626,7 @@ final class HdmiCecController { public void run() { HdmiLogger.debug("[S]:" + cecMessage); byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams()); int i = 0; int retransmissionCount = 0; int errorCode = SendMessageResult.SUCCESS; do { errorCode = mNativeWrapperImpl.nativeSendCecCommand( Loading @@ -627,20 +634,25 @@ final class HdmiCecController { if (errorCode == SendMessageResult.SUCCESS) { break; } } while (i++ < HdmiConfig.RETRANSMISSION_COUNT); } while (retransmissionCount++ < HdmiConfig.RETRANSMISSION_COUNT); final int finalError = errorCode; if (finalError != SendMessageResult.SUCCESS) { Slog.w(TAG, "Failed to send " + cecMessage + " with errorCode=" + finalError); } if (callback != null) { runOnServiceThread(new Runnable() { @Override public void run() { mHdmiCecAtomWriter.messageReported( cecMessage, FrameworkStatsLog.HDMI_CEC_MESSAGE_REPORTED__DIRECTION__OUTGOING, finalError ); if (callback != null) { callback.onSendCompleted(finalError); } }); } }); } }); } Loading @@ -654,9 +666,38 @@ final class HdmiCecController { HdmiCecMessage command = HdmiCecMessageBuilder.of(srcAddress, dstAddress, body); HdmiLogger.debug("[R]:" + command); addCecMessageToHistory(true /* isReceived */, command); mHdmiCecAtomWriter.messageReported(command, incomingMessageDirection(srcAddress, dstAddress)); onReceiveCommand(command); } /** * Computes the direction of an incoming message, as implied by the source and * destination addresses. This will usually return INCOMING; if not, it can indicate a bug. */ private int incomingMessageDirection(int srcAddress, int dstAddress) { boolean sourceIsLocal = false; boolean destinationIsLocal = false; for (HdmiCecLocalDevice localDevice : getLocalDeviceList()) { int logicalAddress = localDevice.getDeviceInfo().getLogicalAddress(); if (logicalAddress == srcAddress) { sourceIsLocal = true; } if (logicalAddress == dstAddress) { destinationIsLocal = true; } } if (!sourceIsLocal && destinationIsLocal) { return HdmiStatsEnums.INCOMING; } else if (sourceIsLocal && destinationIsLocal) { return HdmiStatsEnums.TO_SELF; } return HdmiStatsEnums.MESSAGE_DIRECTION_OTHER; } /** * Called when a hotplug event issues. */ Loading
services/core/java/com/android/server/hdmi/HdmiControlService.java +14 −1 Original line number Diff line number Diff line Loading @@ -397,6 +397,10 @@ public class HdmiControlService extends SystemService { // Set to true if the logical address allocation is completed. private boolean mAddressAllocated = false; // Object that handles logging statsd atoms. // Use getAtomWriter() instead of accessing directly, to allow dependency injection for testing. private HdmiCecAtomWriter mAtomWriter = new HdmiCecAtomWriter(); // Buffer for processing the incoming cec messages while allocating logical addresses. private final class CecMessageBuffer { private List<HdmiCecMessage> mBuffer = new ArrayList<>(); Loading Loading @@ -509,7 +513,7 @@ public class HdmiControlService extends SystemService { mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true); if (mCecController == null) { mCecController = HdmiCecController.create(this); mCecController = HdmiCecController.create(this, getAtomWriter()); } if (mCecController != null) { if (mHdmiControlEnabled) { Loading Loading @@ -3233,6 +3237,10 @@ public class HdmiControlService extends SystemService { mActiveSource.logicalAddress = logicalAddress; mActiveSource.physicalAddress = physicalAddress; } getAtomWriter().activeSourceChanged(logicalAddress, physicalAddress, HdmiUtils.pathRelationship(getPhysicalAddress(), physicalAddress)); // If the current device is a source device, check if the current Active Source matches // the local device info. Set mIsActiveSource of the local device accordingly. for (HdmiCecLocalDevice device : getAllLocalDevices()) { Loading Loading @@ -3363,6 +3371,11 @@ public class HdmiControlService extends SystemService { } } @VisibleForTesting HdmiCecAtomWriter getAtomWriter() { return mAtomWriter; } boolean isMhlInputChangeEnabled() { synchronized (mLock) { return mMhlInputChangeEnabled; Loading
services/tests/servicestests/src/com/android/server/hdmi/ActiveSourceActionTest.java +1 −1 Original line number Diff line number Diff line Loading @@ -110,7 +110,7 @@ public class ActiveSourceActionTest { mHdmiControlService.setIoLooper(looper); mNativeWrapper = new FakeNativeWrapper(); HdmiCecController hdmiCecController = HdmiCecController.createWithNativeWrapper( this.mHdmiControlService, mNativeWrapper); this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); mHdmiControlService.setCecController(hdmiCecController); mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); Loading
services/tests/servicestests/src/com/android/server/hdmi/ArcInitiationActionFromAvrTest.java +2 −2 Original line number Diff line number Diff line Loading @@ -137,8 +137,8 @@ public class ArcInitiationActionFromAvrTest { Looper looper = mTestLooper.getLooper(); mHdmiControlService.setIoLooper(looper); mNativeWrapper = new FakeNativeWrapper(); mHdmiCecController = HdmiCecController.createWithNativeWrapper(this.mHdmiControlService, mNativeWrapper); mHdmiCecController = HdmiCecController.createWithNativeWrapper( this.mHdmiControlService, mNativeWrapper, mHdmiControlService.getAtomWriter()); mHdmiControlService.setCecController(mHdmiCecController); mHdmiControlService.setHdmiMhlController(HdmiMhlControllerStub.create(mHdmiControlService)); mHdmiControlService.setMessageValidator(new HdmiCecMessageValidator(mHdmiControlService)); Loading