diff options
author | Jungshik Jang <jayjang@google.com> | 2014-06-02 04:35:34 +0000 |
---|---|---|
committer | Android (Google) Code Review <android-gerrit@google.com> | 2014-06-02 04:35:35 +0000 |
commit | 37554062ed37c90aecdf7d453013e4bcae9e4c3c (patch) | |
tree | 3e9ae4ab7b231a36f6ff2f5bf421ee008744dfbf | |
parent | dc6adf5c62064213705820a520bd1415fd8670f3 (diff) | |
parent | c47e26ca2ff6f032c4b3a094810b1d1062bcb1ff (diff) | |
download | frameworks_base-37554062ed37c90aecdf7d453013e4bcae9e4c3c.zip frameworks_base-37554062ed37c90aecdf7d453013e4bcae9e4c3c.tar.gz frameworks_base-37554062ed37c90aecdf7d453013e4bcae9e4c3c.tar.bz2 |
Merge "DO NOT MERGE: Add cec message handler to hdmi cec jni implementation" into lmp-preview-dev
3 files changed, 169 insertions, 81 deletions
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java index 3c18a59..19fdaf4 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecController.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -21,6 +21,7 @@ import android.hardware.hdmi.HdmiCecDeviceInfo; import android.hardware.hdmi.HdmiCecMessage; import android.os.Handler; import android.os.Looper; +import android.os.MessageQueue; import android.util.Slog; import android.util.SparseArray; @@ -29,7 +30,6 @@ import com.android.server.hdmi.HdmiControlService.DevicePollingCallback; import libcore.util.EmptyArray; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; /** @@ -99,7 +99,7 @@ final class HdmiCecController { */ static HdmiCecController create(HdmiControlService service) { HdmiCecController controller = new HdmiCecController(); - long nativePtr = nativeInit(controller); + long nativePtr = nativeInit(controller, service.getServiceLooper().getQueue()); if (nativePtr == 0L) { controller = null; return null; @@ -471,8 +471,8 @@ final class HdmiCecController { private void onReceiveCommand(HdmiCecMessage message) { assertRunOnServiceThread(); - if (isAcceptableAddress(message.getDestination()) && - mService.handleCecCommand(message)) { + if (isAcceptableAddress(message.getDestination()) + && mService.handleCecCommand(message)) { return; } @@ -517,17 +517,8 @@ final class HdmiCecController { * Called by native when incoming CEC message arrived. */ private void handleIncomingCecCommand(int srcAddress, int dstAddress, byte[] body) { - byte opcode = body[0]; - byte params[] = Arrays.copyOfRange(body, 1, body.length); - final HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, dstAddress, opcode, params); - - // Delegate message to main handler so that it handles in main thread. - runOnServiceThread(new Runnable() { - @Override - public void run() { - onReceiveCommand(cecMessage); - } - }); + assertRunOnServiceThread(); + onReceiveCommand(HdmiCecMessageBuilder.of(srcAddress, dstAddress, body)); } /** @@ -539,7 +530,7 @@ final class HdmiCecController { mService.onHotplug(0, connected); } - private static native long nativeInit(HdmiCecController handler); + private static native long nativeInit(HdmiCecController handler, MessageQueue messageQueue); private static native int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress, byte[] body); private static native int nativeAddLogicalAddress(long controllerPtr, int logicalAddress); diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java index be270b9..1da363b 100644 --- a/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java +++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java @@ -20,6 +20,7 @@ import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecMessage; import java.io.UnsupportedEncodingException; +import java.util.Arrays; /** * A helper class to build {@link HdmiCecMessage} from various cec commands. @@ -39,6 +40,20 @@ public class HdmiCecMessageBuilder { private HdmiCecMessageBuilder() {} /** + * Build {@link HdmiCecMessage} from raw data. + * + * @param src source address of command + * @param dest destination address of command + * @param body body of message. It includes opcode. + * @return newly created {@link HdmiCecMessage} + */ + static HdmiCecMessage of(int src, int dest, byte[] body) { + byte opcode = body[0]; + byte params[] = Arrays.copyOfRange(body, 1, body.length); + return new HdmiCecMessage(src, dest, opcode, params); + } + + /** * Build <Feature Abort> command. <Feature Abort> consists of * 1 byte original opcode and 1 byte reason fields with basic fields. * diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp index 27c8876..c6de676 100644 --- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp +++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp @@ -21,12 +21,15 @@ #include "JNIHelp.h" #include "ScopedPrimitiveArray.h" -#include <string> +#include <cstring> +#include <android_os_MessageQueue.h> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> #include <hardware/hdmi_cec.h> #include <sys/param.h> +#include <utils/Looper.h> +#include <utils/RefBase.h> namespace android { @@ -37,7 +40,8 @@ static struct { class HdmiCecController { public: - HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj); + HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj, + const sp<Looper>& looper); void init(); @@ -54,49 +58,135 @@ public: // Get vendor id used for vendor command. uint32_t getVendorId(); -private: - // Propagate the message up to Java layer. - void propagateCecCommand(const cec_message_t& message); - void propagateHotplugEvent(const hotplug_event_t& event); + jobject getCallbacksObj() const { + return mCallbacksObj; + } +private: static void onReceived(const hdmi_event_t* event, void* arg); - static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName); hdmi_cec_device_t* mDevice; jobject mCallbacksObj; + sp<Looper> mLooper; }; -HdmiCecController::HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj) : - mDevice(device), - mCallbacksObj(callbacksObj) { -} +// RefBase wrapper for hdmi_event_t. As hdmi_event_t coming from HAL +// may keep its own lifetime, we need to copy it in order to delegate +// it to service thread. +class CecEventWrapper : public LightRefBase<CecEventWrapper> { +public: + CecEventWrapper(const hdmi_event_t& event) { + // Copy message. + switch (event.type) { + case HDMI_EVENT_CEC_MESSAGE: + mEvent.cec.initiator = event.cec.initiator; + mEvent.cec.destination = event.cec.destination; + mEvent.cec.length = event.cec.length; + std::memcpy(mEvent.cec.body, event.cec.body, event.cec.length); + break; + case HDMI_EVENT_HOT_PLUG: + mEvent.hotplug.connected = event.hotplug.connected; + mEvent.hotplug.port = event.hotplug.port; + break; + case HDMI_EVENT_TX_STATUS: + mEvent.tx_status.status = event.tx_status.status; + mEvent.tx_status.opcode = event.tx_status.opcode; + break; + default: + // TODO: add more type whenever new type is introduced. + break; + } + } -void HdmiCecController::init() { - mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this); -} + const cec_message_t& cec() const { + return mEvent.cec; + } -void HdmiCecController::propagateCecCommand(const cec_message_t& message) { - jint srcAddr = message.initiator; - jint dstAddr = message.destination; - JNIEnv* env = AndroidRuntime::getJNIEnv(); - jbyteArray body = env->NewByteArray(message.length); - const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body); - env->SetByteArrayRegion(body, 0, message.length, bodyPtr); + const hotplug_event_t& hotplug() const { + return mEvent.hotplug; + } - env->CallVoidMethod(mCallbacksObj, - gHdmiCecControllerClassInfo.handleIncomingCecCommand, - srcAddr, dstAddr, body); - env->DeleteLocalRef(body); + virtual ~CecEventWrapper() {} - checkAndClearExceptionFromCallback(env, __FUNCTION__); -} +private: + hdmi_event_t mEvent; +}; -void HdmiCecController::propagateHotplugEvent(const hotplug_event_t& event) { - JNIEnv* env = AndroidRuntime::getJNIEnv(); - env->CallVoidMethod(mCallbacksObj, - gHdmiCecControllerClassInfo.handleHotplug, event.connected); +// Handler class to delegate incoming message to service thread. +class HdmiCecEventHandler : public MessageHandler { +public: + HdmiCecEventHandler(HdmiCecController* controller, const sp<CecEventWrapper>& event) + : mController(controller), + mEventWrapper(event) { + } + + virtual ~HdmiCecEventHandler() {} + + void handleMessage(const Message& message) { + switch (message.what) { + case HDMI_EVENT_CEC_MESSAGE: + propagateCecCommand(mEventWrapper->cec()); + break; + case HDMI_EVENT_HOT_PLUG: + propagateHotplugEvent(mEventWrapper->hotplug()); + break; + case HDMI_EVENT_TX_STATUS: + // TODO: propagate this to controller. + default: + // TODO: add more type whenever new type is introduced. + break; + } + } - checkAndClearExceptionFromCallback(env, __FUNCTION__); +private: + // Propagate the message up to Java layer. + void propagateCecCommand(const cec_message_t& message) { + jint srcAddr = message.initiator; + jint dstAddr = message.destination; + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jbyteArray body = env->NewByteArray(message.length); + const jbyte* bodyPtr = reinterpret_cast<const jbyte *>(message.body); + env->SetByteArrayRegion(body, 0, message.length, bodyPtr); + + env->CallVoidMethod(mController->getCallbacksObj(), + gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr, + dstAddr, body); + env->DeleteLocalRef(body); + + checkAndClearExceptionFromCallback(env, __FUNCTION__); + } + + void propagateHotplugEvent(const hotplug_event_t& event) { + // Note that this method should be called in service thread. + JNIEnv* env = AndroidRuntime::getJNIEnv(); + env->CallVoidMethod(mController->getCallbacksObj(), + gHdmiCecControllerClassInfo.handleHotplug, event.connected); + + checkAndClearExceptionFromCallback(env, __FUNCTION__); + } + + // static + static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) { + if (env->ExceptionCheck()) { + ALOGE("An exception was thrown by callback '%s'.", methodName); + LOGE_EX(env); + env->ExceptionClear(); + } + } + + HdmiCecController* mController; + sp<CecEventWrapper> mEventWrapper; +}; + +HdmiCecController::HdmiCecController(hdmi_cec_device_t* device, + jobject callbacksObj, const sp<Looper>& looper) : + mDevice(device), + mCallbacksObj(callbacksObj), + mLooper(looper) { +} + +void HdmiCecController::init() { + mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this); } int HdmiCecController::sendMessage(const cec_message_t& message) { @@ -132,15 +222,6 @@ uint32_t HdmiCecController::getVendorId() { return vendorId; } -// static -void HdmiCecController::checkAndClearExceptionFromCallback(JNIEnv* env, - const char* methodName) { - if (env->ExceptionCheck()) { - ALOGE("An exception was thrown by callback '%s'.", methodName); - LOGE_EX(env); - env->ExceptionClear(); - } -} // static void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) { @@ -149,17 +230,9 @@ void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) { return; } - switch (event->type) { - case HDMI_EVENT_CEC_MESSAGE: - controller->propagateCecCommand(event->cec); - break; - case HDMI_EVENT_HOT_PLUG: - controller->propagateHotplugEvent(event->hotplug); - break; - default: - ALOGE("Unsupported event type: %d", event->type); - break; - } + sp<CecEventWrapper> spEvent(new CecEventWrapper(*event)); + sp<HdmiCecEventHandler> handler(new HdmiCecEventHandler(controller, spEvent)); + controller->mLooper->sendMessage(handler, event->type); } //------------------------------------------------------------------------------ @@ -167,31 +240,38 @@ void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) { var = env->GetMethodID(clazz, methodName, methodDescriptor); \ LOG_FATAL_IF(! var, "Unable to find method " methodName); -static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj) { +// TODO: replace above code with following once +// replace old HdmiCecService with HdmiControlService +#undef HDMI_CEC_HARDWARE_MODULE_ID +#define HDMI_CEC_HARDWARE_MODULE_ID "hdmi_cec_module" +#undef HDMI_CEC_HARDWARE_INTERFACE +#define HDMI_CEC_HARDWARE_INTERFACE "hdmi_cec_module_hw_if" + +static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj, + jobject messageQueueObj) { int err; - // If use same hardware module id between HdmiCecService and - // HdmiControlSservice it may conflict and cause abnormal state of HAL. - // TODO: use HDMI_CEC_HARDWARE_MODULE_ID of hdmi_cec.h for module id - // once migration to HdmiControlService is done. hw_module_t* module; - err = hw_get_module("hdmi_cec_module", + err = hw_get_module(HDMI_CEC_HARDWARE_MODULE_ID, const_cast<const hw_module_t **>(&module)); if (err != 0) { ALOGE("Error acquiring hardware module: %d", err); return 0; } + hw_device_t* device; - // TODO: use HDMI_CEC_HARDWARE_INTERFACE of hdmi_cec.h for interface name - // once migration to HdmiControlService is done. - err = module->methods->open(module, "hdmi_cec_module_hw_if", &device); + err = module->methods->open(module, HDMI_CEC_HARDWARE_INTERFACE, &device); if (err != 0) { ALOGE("Error opening hardware module: %d", err); return 0; } + sp<MessageQueue> messageQueue = + android_os_MessageQueue_getMessageQueue(env, messageQueueObj); + HdmiCecController* controller = new HdmiCecController( reinterpret_cast<hdmi_cec_device*>(device), - env->NewGlobalRef(callbacksObj)); + env->NewGlobalRef(callbacksObj), + messageQueue->getLooper()); controller->init(); GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz, @@ -255,8 +335,9 @@ static jint nativeGetVendorId(JNIEnv* env, jclass clazz, jlong controllerPtr) { static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ - { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;)J", - (void *) nativeInit }, + { "nativeInit", + "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J", + (void *) nativeInit }, { "nativeSendCecCommand", "(JII[B)I", (void *) nativeSendCecCommand }, { "nativeAddLogicalAddress", "(JI)I", (void *) nativeAddLogicalAddress }, { "nativeClearLogicalAddress", "(J)V", (void *) nativeClearLogicalAddress }, @@ -268,7 +349,8 @@ static JNINativeMethod sMethods[] = { #define CLASS_PATH "com/android/server/hdmi/HdmiCecController" int register_android_server_hdmi_HdmiCecController(JNIEnv* env) { - int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, NELEM(sMethods)); + int res = jniRegisterNativeMethods(env, CLASS_PATH, sMethods, + NELEM(sMethods)); LOG_FATAL_IF(res < 0, "Unable to register native methods."); return 0; } |