diff options
author | Jungshik Jang <jayjang@google.com> | 2014-05-22 19:28:09 +0900 |
---|---|---|
committer | Jungshik Jang <jayjang@google.com> | 2014-06-02 10:42:03 +0900 |
commit | 404d704158d068c9b1f066ec647461f0f9ec22cd (patch) | |
tree | f42252e60fadb53f9665c8ef2489d500a4210509 /services | |
parent | c6c967b68a9c29e0930bcfa32548633596fe5745 (diff) | |
download | frameworks_base-404d704158d068c9b1f066ec647461f0f9ec22cd.zip frameworks_base-404d704158d068c9b1f066ec647461f0f9ec22cd.tar.gz frameworks_base-404d704158d068c9b1f066ec647461f0f9ec22cd.tar.bz2 |
DO NOT MERGE: Add SendMessageCallback to Hdmi control service.
As we have separate IO thread, we should have async callback
mechanism to get result of send request.
For that, I added SendMessageCallback interface to HdmiControl
Service
Along with this, replace message-based IO handling with
post Runnable based one for consistency
Change-Id: I61cf5b751b4f2af3b34956060869f3512f161d11
Diffstat (limited to 'services')
6 files changed, 184 insertions, 165 deletions
diff --git a/services/core/java/com/android/server/hdmi/FeatureAction.java b/services/core/java/com/android/server/hdmi/FeatureAction.java index 1bc278d..f8e9b7b 100644 --- a/services/core/java/com/android/server/hdmi/FeatureAction.java +++ b/services/core/java/com/android/server/hdmi/FeatureAction.java @@ -164,8 +164,13 @@ abstract class FeatureAction { mActionTimer.sendTimerMessage(state, delayMillis); } - protected final boolean sendCommand(HdmiCecMessage cmd) { - return mService.sendCecCommand(cmd); + protected final void sendCommand(HdmiCecMessage cmd) { + mService.sendCecCommand(cmd); + } + + protected final void sendCommand(HdmiCecMessage cmd, + HdmiControlService.SendMessageCallback callback) { + mService.sendCecCommand(cmd, callback); } /** diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index f99a01d..662159d 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -20,9 +20,6 @@ import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCecMessage; import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; @@ -176,115 +173,66 @@ final class HdmiCecController { * Otherwise, scan address will start from {@code preferredAddress} * @param callback callback interface to report allocated logical address to caller */ - void allocateLogicalAddress(int deviceType, int preferredAddress, - AllocateLogicalAddressCallback callback) { - Message msg = mIoHandler.obtainMessage(MSG_ALLOCATE_LOGICAL_ADDRESS); - msg.arg1 = deviceType; - msg.arg2 = preferredAddress; - msg.obj = callback; - mIoHandler.sendMessage(msg); - } - - private static byte[] buildBody(int opcode, byte[] params) { - byte[] body = new byte[params.length + 1]; - body[0] = (byte) opcode; - System.arraycopy(params, 0, body, 1, params.length); - return body; + void allocateLogicalAddress(final int deviceType, final int preferredAddress, + final AllocateLogicalAddressCallback callback) { + runOnIoThread(new Runnable() { + @Override + public void run() { + handleAllocateLogicalAddress(deviceType, preferredAddress, callback); + } + }); } - private final class IoHandler extends Handler { - private IoHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_SEND_CEC_COMMAND: - HdmiCecMessage cecMessage = (HdmiCecMessage) msg.obj; - byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams()); - nativeSendCecCommand(mNativePtr, cecMessage.getSource(), - cecMessage.getDestination(), body); - break; - case MSG_ALLOCATE_LOGICAL_ADDRESS: - int deviceType = msg.arg1; - int preferredAddress = msg.arg2; - AllocateLogicalAddressCallback callback = - (AllocateLogicalAddressCallback) msg.obj; - handleAllocateLogicalAddress(deviceType, preferredAddress, callback); - break; - default: - Slog.w(TAG, "Unsupported CEC Io request:" + msg.what); + private void handleAllocateLogicalAddress(final int deviceType, int preferredAddress, + final AllocateLogicalAddressCallback callback) { + int startAddress = preferredAddress; + // If preferred address is "unregistered", start address will be the smallest + // address matched with the given device type. + if (preferredAddress == HdmiCec.ADDR_UNREGISTERED) { + for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) { + if (deviceType == HdmiCec.getTypeFromAddress(i)) { + startAddress = i; break; + } } } - private void handleAllocateLogicalAddress(int deviceType, int preferredAddress, - AllocateLogicalAddressCallback callback) { - int startAddress = preferredAddress; - // If preferred address is "unregistered", start_index will be the smallest - // address matched with the given device type. - if (preferredAddress == HdmiCec.ADDR_UNREGISTERED) { - for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) { - if (deviceType == HdmiCec.getTypeFromAddress(i)) { - startAddress = i; - break; - } + int logicalAddress = HdmiCec.ADDR_UNREGISTERED; + // Iterates all possible addresses which has the same device type. + for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) { + int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS; + if (curAddress != HdmiCec.ADDR_UNREGISTERED + && deviceType == HdmiCec.getTypeFromAddress(i)) { + // <Polling Message> is a message which has empty body and + // uses same address for both source and destination address. + // If sending <Polling Message> failed (NAK), it becomes + // new logical address for the device because no device uses + // it as logical address of the device. + int error = nativeSendCecCommand(mNativePtr, curAddress, curAddress, + EMPTY_BODY); + if (error != ERROR_SUCCESS) { + logicalAddress = curAddress; + break; } } + } - int logcialAddress = HdmiCec.ADDR_UNREGISTERED; - // Iterates all possible addresses which has the same device type. - for (int i = 0; i < NUM_LOGICAL_ADDRESS; ++i) { - int curAddress = (startAddress + i) % NUM_LOGICAL_ADDRESS; - if (curAddress != HdmiCec.ADDR_UNREGISTERED - && deviceType == HdmiCec.getTypeFromAddress(i)) { - // <Polling Message> is a message which has empty body and - // uses same address for both source and destination address. - // If sending <Polling Message> failed (NAK), it becomes - // new logical address for the device because no device uses - // it as logical address of the device. - int error = nativeSendCecCommand(mNativePtr, curAddress, curAddress, - EMPTY_BODY); - if (error != ERROR_SUCCESS) { - logcialAddress = curAddress; - break; - } + final int assignedAddress = logicalAddress; + if (callback != null) { + runOnServiceThread(new Runnable() { + @Override + public void run() { + callback.onAllocated(deviceType, assignedAddress); } - } - - Message msg = mControlHandler.obtainMessage(MSG_REPORT_LOGICAL_ADDRESS); - msg.arg1 = deviceType; - msg.arg2 = logcialAddress; - msg.obj = callback; - mControlHandler.sendMessage(msg); + }); } } - private final class ControlHandler extends Handler { - private ControlHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_RECEIVE_CEC_COMMAND: - // TODO: delegate it to HdmiControl service. - onReceiveCommand((HdmiCecMessage) msg.obj); - break; - case MSG_REPORT_LOGICAL_ADDRESS: - int deviceType = msg.arg1; - int logicalAddress = msg.arg2; - AllocateLogicalAddressCallback callback = - (AllocateLogicalAddressCallback) msg.obj; - callback.onAllocated(deviceType, logicalAddress); - break; - default: - Slog.i(TAG, "Unsupported message type:" + msg.what); - break; - } - } + private static byte[] buildBody(int opcode, byte[] params) { + byte[] body = new byte[params.length + 1]; + body[0] = (byte) opcode; + System.arraycopy(params, 0, body, 1, params.length); + return body; } /** @@ -411,10 +359,18 @@ final class HdmiCecController { return nativeGetVendorId(mNativePtr); } + private void runOnIoThread(Runnable runnable) { + mIoHandler.post(runnable); + } + + private void runOnServiceThread(Runnable runnable) { + mControlHandler.post(runnable); + } + private void init(HdmiControlService service, long nativePtr) { mService = service; - mIoHandler = new IoHandler(service.getServiceLooper()); - mControlHandler = new ControlHandler(service.getServiceLooper()); + mIoHandler = new Handler(service.getServiceLooper()); + mControlHandler = new Handler(service.getServiceLooper()); mNativePtr = nativePtr; } @@ -438,13 +394,27 @@ final class HdmiCecController { HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildFeatureAbortCommand (sourceAddress, message.getSource(), message.getOpcode(), HdmiCecMessageBuilder.ABORT_REFUSED); - sendCommand(cecMessage); - + sendCommand(cecMessage, null); } - boolean sendCommand(HdmiCecMessage cecMessage) { - Message message = mIoHandler.obtainMessage(MSG_SEND_CEC_COMMAND, cecMessage); - return mIoHandler.sendMessage(message); + void sendCommand(final HdmiCecMessage cecMessage, + final HdmiControlService.SendMessageCallback callback) { + runOnIoThread(new Runnable() { + @Override + public void run() { + byte[] body = buildBody(cecMessage.getOpcode(), cecMessage.getParams()); + final int error = nativeSendCecCommand(mNativePtr, cecMessage.getSource(), + cecMessage.getDestination(), body); + if (callback != null) { + runOnServiceThread(new Runnable() { + @Override + public void run() { + callback.onSendCompleted(error); + } + }); + } + } + }); } /** @@ -453,12 +423,15 @@ final class HdmiCecController { private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) { byte opcode = body[0]; byte params[] = Arrays.copyOfRange(body, 1, body.length); - HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, dstAddress, opcode, params); + final HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, dstAddress, opcode, params); // Delegate message to main handler so that it handles in main thread. - Message message = mControlHandler.obtainMessage( - MSG_RECEIVE_CEC_COMMAND, cecMessage); - mControlHandler.sendMessage(message); + runOnServiceThread(new Runnable() { + @Override + public void run() { + onReceiveCommand(cecMessage); + } + }); } /** diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java index 09153b9..d7a2c1c 100644 --- a/services/core/java/com/android/server/hdmi/HdmiControlService.java +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -18,30 +18,25 @@ package com.android.server.hdmi; import android.annotation.Nullable; import android.content.Context; -import android.hardware.hdmi.IHdmiControlCallback; -import android.hardware.hdmi.IHdmiControlService; -import android.hardware.hdmi.IHdmiHotplugEventListener; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCecMessage; +import android.hardware.hdmi.IHdmiControlCallback; +import android.hardware.hdmi.IHdmiControlService; +import android.hardware.hdmi.IHdmiHotplugEventListener; import android.os.Handler; import android.os.HandlerThread; import android.os.IBinder; import android.os.Looper; import android.os.RemoteException; import android.util.Slog; -import android.util.SparseArray; - import com.android.internal.annotations.GuardedBy; import com.android.server.SystemService; import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; import java.util.Iterator; import java.util.LinkedList; -import java.util.List; import java.util.Locale; /** @@ -54,6 +49,20 @@ public final class HdmiControlService extends SystemService { // TODO: Rename the permission to HDMI_CONTROL. private static final String PERMISSION = "android.permission.HDMI_CEC"; + /** + * Interface to report send result. + */ + interface SendMessageCallback { + /** + * Called when {@link HdmiControlService#sendCecCommand} is completed. + * + * @param error result of send request. 0 if succeed. Otherwise it will be + * negative value + */ + // TODO: define error code as constants and update javadoc. + void onSendCompleted(int error); + } + // A thread to handle synchronous IO of CEC and MHL control service. // Since all of CEC and MHL HAL interfaces processed in short time (< 200ms) // and sparse call it shares a thread to handle IO operations. @@ -205,10 +214,14 @@ public final class HdmiControlService extends SystemService { * Transmit a CEC command to CEC bus. * * @param command CEC command to send out - * @return {@code true} if succeeds to send command + * @param callback interface used to the result of send command */ - boolean sendCecCommand(HdmiCecMessage command) { - return mCecController.sendCommand(command); + void sendCecCommand(HdmiCecMessage command, @Nullable SendMessageCallback callback) { + mCecController.sendCommand(command, callback); + } + + void sendCecCommand(HdmiCecMessage command) { + mCecController.sendCommand(command, null); } /** diff --git a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java index 0a701f9..db9d28d 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcInitiationAction.java @@ -16,6 +16,7 @@ package com.android.server.hdmi; +import android.hardware.hdmi.HdmiCecMessage; import android.util.Slog; /** @@ -37,17 +38,24 @@ final class RequestArcInitiationAction extends RequestArcAction { @Override boolean start() { - if (sendCommand( - HdmiCecMessageBuilder.buildRequestArcInitiation(mSourceAddress, mAvrAddress))) { - mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE; - addTimer(mState, TIMEOUT_MS); - } else { - Slog.w(TAG, "Failed to send <Request ARC Initiation>"); - // If failed to send <Request ARC Initiation>, start "Disabled" ARC transmission - // action. - disableArcTransmission(); - finish(); - } + HdmiCecMessage command = HdmiCecMessageBuilder.buildRequestArcInitiation(mSourceAddress, + mAvrAddress); + sendCommand(command, new HdmiControlService.SendMessageCallback() { + @Override + public void onSendCompleted(int error) { + // success. + if (error == 0) { + mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE; + addTimer(mState, TIMEOUT_MS); + } else { + Slog.w(TAG, "Failed to send <Request ARC Initiation>"); + // If failed to send <Request ARC Initiation>, start "Disabled" + // ARC transmission action. + disableArcTransmission(); + finish(); + } + } + }); return true; } } diff --git a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java index db1b992..7669f87 100644 --- a/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java +++ b/services/core/java/com/android/server/hdmi/RequestArcTerminationAction.java @@ -16,6 +16,7 @@ package com.android.server.hdmi; +import android.hardware.hdmi.HdmiCecMessage; import android.util.Slog; /** @@ -37,17 +38,23 @@ final class RequestArcTerminationAction extends RequestArcAction { @Override boolean start() { - if (sendCommand( - HdmiCecMessageBuilder.buildRequestArcTermination(mSourceAddress, mAvrAddress))) { - mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE; - addTimer(mState, TIMEOUT_MS); - } else { - Slog.w(TAG, "Failed to send <Request ARC Initiation>"); - // If failed to send <Request ARC Termination>, start "Disabled" ARC transmission - // action. - disableArcTransmission(); - finish(); - } + HdmiCecMessage command = + HdmiCecMessageBuilder.buildRequestArcTermination(mSourceAddress, mAvrAddress); + sendCommand(command, new HdmiControlService.SendMessageCallback() { + @Override + public void onSendCompleted(int error) { + if (error == 0) { + mState = STATE_WATING_FOR_REQUEST_ARC_REQUEST_RESPONSE; + addTimer(mState, TIMEOUT_MS); + } else { + Slog.w(TAG, "Failed to send <Request ARC Initiation>"); + // If failed to send <Request ARC Termination>, start "Disabled" ARC + // transmission action. + disableArcTransmission(); + finish(); + } + } + }); return true; } } diff --git a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java index 6bf149b..94776a2 100644 --- a/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java +++ b/services/core/java/com/android/server/hdmi/SetArcTransmissionStateAction.java @@ -64,26 +64,7 @@ final class SetArcTransmissionStateAction extends FeatureAction { @Override boolean start() { if (mEnabled) { - if (sendCommand( - HdmiCecMessageBuilder.buildReportArcInitiated(mSourceAddress, mAvrAddress))) { - // Enable ARC status immediately after sending <Report Arc Initiated>. - // If AVR responds with <Feature Abort>, disable ARC status again. - // This is different from spec that says that turns ARC status to "Enabled" - // if <Report ARC Initiated> is acknowledged and no <Feature Abort> is received. - // But implemented this way to save the time having to wait for <Feature Abort>. - setArcStatus(true); - // If succeeds to send <Report ARC Initiated>, wait general timeout - // to check whether there is no <Feature Abort> for <Report ARC Initiated>. - mState = STATE_WAITING_TIMEOUT; - addTimer(mState, TIMEOUT_MS); - } else { - // If fails to send <Report ARC Initiated>, disable ARC and - // send <Report ARC Terminated> directly. - Slog.w(TAG, "Failed to send <Report ARC Initiated>:[source:" + mSourceAddress - + ", avr Address:" + mAvrAddress + "]"); - setArcStatus(false); - finish(); - } + sendReportArcInitiated(); } else { setArcStatus(false); finish(); @@ -91,6 +72,38 @@ final class SetArcTransmissionStateAction extends FeatureAction { return true; } + private void sendReportArcInitiated() { + HdmiCecMessage command = + HdmiCecMessageBuilder.buildReportArcInitiated(mSourceAddress, mAvrAddress); + sendCommand(command, new HdmiControlService.SendMessageCallback() { + @Override + public void onSendCompleted(int error) { + if (error == 0) { + // Enable ARC status immediately after sending <Report Arc Initiated>. + // If AVR responds with <Feature Abort>, disable ARC status again. + // This is different from spec that says that turns ARC status to + // "Enabled" if <Report ARC Initiated> is acknowledged and no + // <Feature Abort> is received. + // But implemented this way to save the time having to wait for + // <Feature Abort>. + setArcStatus(true); + // If succeeds to send <Report ARC Initiated>, wait general timeout + // to check whether there is no <Feature Abort> for <Report ARC Initiated>. + mState = STATE_WAITING_TIMEOUT; + addTimer(mState, TIMEOUT_MS); + } else { + // If fails to send <Report ARC Initiated>, disable ARC and + // send <Report ARC Terminated> directly. + Slog.w(TAG, "Failed to send <Report ARC Initiated>:[source:" + + mSourceAddress + + ", avr Address:" + mAvrAddress + "]"); + setArcStatus(false); + finish(); + } + } + }); + } + private void setArcStatus(boolean enabled) { boolean wasEnabled = mService.setArcStatus(enabled); Slog.i(TAG, "Change arc status [old:" + wasEnabled + " ,new:" + enabled); |