CEC: Buffer Cec messages while allocating logical address
CEC messages arriving before logical address allocation was being discarded. Handles them by introducing a message buffer class to keep them till the address allocation is finished. Also updated per-device message buffer to use copied version of messages list for iterating to avoid the possible concurrent modification exception. Bug: 18896770 Change-Id: Ifb74fd265510de6dde322e0b3bc5b504fecb4daa
This commit is contained in:
@@ -77,11 +77,13 @@ final class DelayedMessageBuffer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void processAllMessages() {
|
void processAllMessages() {
|
||||||
for (HdmiCecMessage message : mBuffer) {
|
// Use the copied buffer.
|
||||||
|
ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<HdmiCecMessage>(mBuffer);
|
||||||
|
mBuffer.clear();
|
||||||
|
for (HdmiCecMessage message : copiedBuffer) {
|
||||||
mDevice.onMessage(message);
|
mDevice.onMessage(message);
|
||||||
HdmiLogger.debug("Processing message:" + message);
|
HdmiLogger.debug("Processing message:" + message);
|
||||||
}
|
}
|
||||||
mBuffer.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -95,15 +97,21 @@ final class DelayedMessageBuffer {
|
|||||||
* are associated with
|
* are associated with
|
||||||
*/
|
*/
|
||||||
void processMessagesForDevice(int address) {
|
void processMessagesForDevice(int address) {
|
||||||
|
ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<HdmiCecMessage>(mBuffer);
|
||||||
|
mBuffer.clear();
|
||||||
HdmiLogger.debug("Checking message for address:" + address);
|
HdmiLogger.debug("Checking message for address:" + address);
|
||||||
for (Iterator<HdmiCecMessage> iter = mBuffer.iterator(); iter.hasNext(); ) {
|
for (HdmiCecMessage message : copiedBuffer) {
|
||||||
HdmiCecMessage message = iter.next();
|
if (message.getSource() != address) {
|
||||||
if (message.getSource() != address) continue;
|
mBuffer.add(message);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE
|
if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE
|
||||||
&& !mDevice.isInputReady(HdmiDeviceInfo.idForCecDevice(address))) continue;
|
&& !mDevice.isInputReady(HdmiDeviceInfo.idForCecDevice(address))) {
|
||||||
|
mBuffer.add(message);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
mDevice.onMessage(message);
|
mDevice.onMessage(message);
|
||||||
HdmiLogger.debug("Processing message:" + message);
|
HdmiLogger.debug("Processing message:" + message);
|
||||||
iter.remove();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,13 +127,15 @@ final class DelayedMessageBuffer {
|
|||||||
* @param address logical address of the device to be the active source
|
* @param address logical address of the device to be the active source
|
||||||
*/
|
*/
|
||||||
void processActiveSource(int address) {
|
void processActiveSource(int address) {
|
||||||
for (Iterator<HdmiCecMessage> iter = mBuffer.iterator(); iter.hasNext(); ) {
|
ArrayList<HdmiCecMessage> copiedBuffer = new ArrayList<HdmiCecMessage>(mBuffer);
|
||||||
HdmiCecMessage message = iter.next();
|
mBuffer.clear();
|
||||||
|
for (HdmiCecMessage message : copiedBuffer) {
|
||||||
if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE
|
if (message.getOpcode() == Constants.MESSAGE_ACTIVE_SOURCE
|
||||||
&& message.getSource() == address) {
|
&& message.getSource() == address) {
|
||||||
mDevice.onMessage(message);
|
mDevice.onMessage(message);
|
||||||
HdmiLogger.debug("Processing message:" + message);
|
HdmiLogger.debug("Processing message:" + message);
|
||||||
iter.remove();
|
} else {
|
||||||
|
mBuffer.add(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -286,6 +286,69 @@ public final class HdmiControlService extends SystemService {
|
|||||||
@ServiceThreadOnly
|
@ServiceThreadOnly
|
||||||
private int mLastInputMhl = Constants.INVALID_PORT_ID;
|
private int mLastInputMhl = Constants.INVALID_PORT_ID;
|
||||||
|
|
||||||
|
// Set to true if the logical address allocation is completed.
|
||||||
|
private boolean mAddressAllocated = false;
|
||||||
|
|
||||||
|
// Buffer for processing the incoming cec messages while allocating logical addresses.
|
||||||
|
private final class CecMessageBuffer {
|
||||||
|
private List<HdmiCecMessage> mBuffer = new ArrayList<>();
|
||||||
|
|
||||||
|
public void bufferMessage(HdmiCecMessage message) {
|
||||||
|
switch (message.getOpcode()) {
|
||||||
|
case Constants.MESSAGE_ACTIVE_SOURCE:
|
||||||
|
bufferActiveSource(message);
|
||||||
|
break;
|
||||||
|
case Constants.MESSAGE_IMAGE_VIEW_ON:
|
||||||
|
case Constants.MESSAGE_TEXT_VIEW_ON:
|
||||||
|
bufferImageOrTextViewOn(message);
|
||||||
|
break;
|
||||||
|
// Add here if new message that needs to buffer
|
||||||
|
default:
|
||||||
|
// Do not need to buffer messages other than above
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void processMessages() {
|
||||||
|
for (final HdmiCecMessage message : mBuffer) {
|
||||||
|
runOnServiceThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
handleCecCommand(message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
mBuffer.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bufferActiveSource(HdmiCecMessage message) {
|
||||||
|
if (!replaceMessageIfBuffered(message, Constants.MESSAGE_ACTIVE_SOURCE)) {
|
||||||
|
mBuffer.add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void bufferImageOrTextViewOn(HdmiCecMessage message) {
|
||||||
|
if (!replaceMessageIfBuffered(message, Constants.MESSAGE_IMAGE_VIEW_ON) &&
|
||||||
|
!replaceMessageIfBuffered(message, Constants.MESSAGE_TEXT_VIEW_ON)) {
|
||||||
|
mBuffer.add(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the message is replaced
|
||||||
|
private boolean replaceMessageIfBuffered(HdmiCecMessage message, int opcode) {
|
||||||
|
for (int i = 0; i < mBuffer.size(); i++) {
|
||||||
|
HdmiCecMessage bufferedMessage = mBuffer.get(i);
|
||||||
|
if (bufferedMessage.getOpcode() == opcode) {
|
||||||
|
mBuffer.set(i, message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private CecMessageBuffer mCecMessageBuffer = new CecMessageBuffer();
|
||||||
|
|
||||||
public HdmiControlService(Context context) {
|
public HdmiControlService(Context context) {
|
||||||
super(context);
|
super(context);
|
||||||
mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE));
|
mLocalDevices = getIntList(SystemProperties.get(Constants.PROPERTY_DEVICE_TYPE));
|
||||||
@@ -474,6 +537,7 @@ public final class HdmiControlService extends SystemService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initializeCec(int initiatedBy) {
|
private void initializeCec(int initiatedBy) {
|
||||||
|
mAddressAllocated = false;
|
||||||
mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED);
|
mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, ENABLED);
|
||||||
initializeLocalDevices(initiatedBy);
|
initializeLocalDevices(initiatedBy);
|
||||||
}
|
}
|
||||||
@@ -504,6 +568,8 @@ public final class HdmiControlService extends SystemService {
|
|||||||
mCecController.clearLogicalAddress();
|
mCecController.clearLogicalAddress();
|
||||||
final ArrayList<HdmiCecLocalDevice> allocatedDevices = new ArrayList<>();
|
final ArrayList<HdmiCecLocalDevice> allocatedDevices = new ArrayList<>();
|
||||||
final int[] finished = new int[1];
|
final int[] finished = new int[1];
|
||||||
|
mAddressAllocated = allocatingDevices.isEmpty();
|
||||||
|
|
||||||
for (final HdmiCecLocalDevice localDevice : allocatingDevices) {
|
for (final HdmiCecLocalDevice localDevice : allocatingDevices) {
|
||||||
mCecController.allocateLogicalAddress(localDevice.getType(),
|
mCecController.allocateLogicalAddress(localDevice.getType(),
|
||||||
localDevice.getPreferredAddress(), new AllocateAddressCallback() {
|
localDevice.getPreferredAddress(), new AllocateAddressCallback() {
|
||||||
@@ -524,12 +590,14 @@ public final class HdmiControlService extends SystemService {
|
|||||||
|
|
||||||
// Address allocation completed for all devices. Notify each device.
|
// Address allocation completed for all devices. Notify each device.
|
||||||
if (allocatingDevices.size() == ++finished[0]) {
|
if (allocatingDevices.size() == ++finished[0]) {
|
||||||
|
mAddressAllocated = true;
|
||||||
if (initiatedBy != INITIATED_BY_HOTPLUG) {
|
if (initiatedBy != INITIATED_BY_HOTPLUG) {
|
||||||
// In case of the hotplug we don't call onInitializeCecComplete()
|
// In case of the hotplug we don't call onInitializeCecComplete()
|
||||||
// since we reallocate the logical address only.
|
// since we reallocate the logical address only.
|
||||||
onInitializeCecComplete(initiatedBy);
|
onInitializeCecComplete(initiatedBy);
|
||||||
}
|
}
|
||||||
notifyAddressAllocated(allocatedDevices, initiatedBy);
|
notifyAddressAllocated(allocatedDevices, initiatedBy);
|
||||||
|
mCecMessageBuffer.processMessages();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -762,6 +830,10 @@ public final class HdmiControlService extends SystemService {
|
|||||||
@ServiceThreadOnly
|
@ServiceThreadOnly
|
||||||
boolean handleCecCommand(HdmiCecMessage message) {
|
boolean handleCecCommand(HdmiCecMessage message) {
|
||||||
assertRunOnServiceThread();
|
assertRunOnServiceThread();
|
||||||
|
if (!mAddressAllocated) {
|
||||||
|
mCecMessageBuffer.bufferMessage(message);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
int errorCode = mMessageValidator.isValid(message);
|
int errorCode = mMessageValidator.isValid(message);
|
||||||
if (errorCode != HdmiCecMessageValidator.OK) {
|
if (errorCode != HdmiCecMessageValidator.OK) {
|
||||||
// We'll not response on the messages with the invalid source or destination
|
// We'll not response on the messages with the invalid source or destination
|
||||||
@@ -1990,6 +2062,7 @@ public final class HdmiControlService extends SystemService {
|
|||||||
device.onStandby(mStandbyMessageReceived);
|
device.onStandby(mStandbyMessageReceived);
|
||||||
}
|
}
|
||||||
mStandbyMessageReceived = false;
|
mStandbyMessageReceived = false;
|
||||||
|
mAddressAllocated = false;
|
||||||
mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED);
|
mCecController.setOption(OPTION_CEC_SERVICE_CONTROL, DISABLED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user