Loading services/core/java/com/android/server/hdmi/HdmiCecController.java +115 −17 Original line number Diff line number Diff line Loading @@ -16,9 +16,14 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecMessage; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Slog; import java.util.Arrays; /** * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command Loading @@ -32,12 +37,27 @@ import android.os.Message; class HdmiCecController { private static final String TAG = "HdmiCecController"; // A message to pass cec send command to IO looper. private static final int MSG_SEND_CEC_COMMAND = 1; // Message types to handle incoming message in main service looper. private final static int MSG_RECEIVE_CEC_COMMAND = 1; // TODO: move these values to HdmiCec.java once make it internal constant class. // CEC's ABORT reason values. private static final int ABORT_UNRECOGNIZED_MODE = 0; private static final int ABORT_NOT_IN_CORRECT_MODE = 1; private static final int ABORT_CANNOT_PROVIDE_SOURCE = 2; private static final int ABORT_INVALID_OPERAND = 3; private static final int ABORT_REFUSED = 4; private static final int ABORT_UNABLE_TO_DETERMINE = 5; // Handler instance to process synchronous I/O (mainly send) message. private Handler mIoHandler; // Handler instance to process various messages coming from other CEC // device or issued by internal state change. private Handler mMessageHandler; private Handler mControlHandler; // Stores the pointer to the native implementation of the service that // interacts with HAL. Loading @@ -52,14 +72,12 @@ class HdmiCecController { * inner device or has no device it will return {@code null}. * * <p>Declared as package-private, accessed by {@link HdmiControlService} only. * * @param ioLooper a Looper instance to handle IO (mainly send message) operation. * @param messageHandler a message handler that processes a message coming from other * CEC compatible device or callback of internal state change. * @param service {@link HdmiControlService} instance used to create internal handler * and to pass callback for incoming message or event. * @return {@link HdmiCecController} if device is initialized successfully. Otherwise, * returns {@code null}. */ static HdmiCecController create(Looper ioLooper, Handler messageHandler) { static HdmiCecController create(HdmiControlService service) { HdmiCecController handler = new HdmiCecController(); long nativePtr = nativeInit(handler); if (nativePtr == 0L) { Loading @@ -67,28 +85,108 @@ class HdmiCecController { return null; } handler.init(ioLooper, messageHandler, nativePtr); handler.init(service, nativePtr); return handler; } private void init(Looper ioLooper, Handler messageHandler, long nativePtr) { mIoHandler = new Handler(ioLooper) { 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; } 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; default: Slog.w(TAG, "Unsupported CEC Io request:" + msg.what); break; } } } private final class ControlHandler extends Handler { private ControlHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // TODO: Call native sendMessage. switch (msg.what) { case MSG_RECEIVE_CEC_COMMAND: // TODO: delegate it to HdmiControl service. onReceiveCommand((HdmiCecMessage) msg.obj); break; default: Slog.i(TAG, "Unsupported message type:" + msg.what); break; } } } }; mMessageHandler = messageHandler; private void init(HdmiControlService service, long nativePtr) { mIoHandler = new IoHandler(service.getServiceLooper()); mControlHandler = new ControlHandler(service.getServiceLooper()); mNativePtr = nativePtr; } private void onReceiveCommand(HdmiCecMessage message) { // TODO: Handle message according to opcode type. // TODO: Use device's source address for broadcast message. int sourceAddress = message.getDestination() != HdmiCec.ADDR_BROADCAST ? message.getDestination() : 0; // Reply <Feature Abort> to initiator (source) for all requests. sendFeatureAbort(sourceAddress, message.getSource(), message.getOpcode(), ABORT_REFUSED); } private void sendFeatureAbort(int srcAddress, int destAddress, int originalOpcode, int reason) { byte[] params = new byte[2]; params[0] = (byte) originalOpcode; params[1] = (byte) reason; HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, destAddress, HdmiCec.MESSAGE_FEATURE_ABORT, params); Message message = mIoHandler.obtainMessage(MSG_SEND_CEC_COMMAND, cecMessage); mIoHandler.sendMessage(message); } /** * 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); 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); } /** * Called by native when an HDMI-CEC message arrived. * Called by native when a hotplug event issues. */ private void handleMessage(int srcAddress, int dstAddres, int opcode, byte[] params) { // TODO: Translate message and delegate it to main message handler. private void handleHotplug(boolean connected) { // TODO: Delegate event to main message handler. } private static native long nativeInit(HdmiCecController handler); private static native int nativeSendCecCommand(long contollerPtr, int srcAddress, int dstAddress, byte[] body); } services/core/java/com/android/server/hdmi/HdmiControlService.java +22 −12 Original line number Diff line number Diff line Loading @@ -18,9 +18,8 @@ package com.android.server.hdmi; import android.annotation.Nullable; import android.content.Context; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.os.Looper; import android.util.Slog; import com.android.server.SystemService; Loading @@ -37,14 +36,6 @@ public final class HdmiControlService extends SystemService { // and sparse call it shares a thread to handle IO operations. private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); // Main handler class to handle incoming message from each controller. private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // TODO: Add handler for each message type. } }; @Nullable private HdmiCecController mCecController; Loading @@ -57,14 +48,33 @@ public final class HdmiControlService extends SystemService { @Override public void onStart() { mCecController = HdmiCecController.create(mIoThread.getLooper(), mHandler); mCecController = HdmiCecController.create(this); if (mCecController == null) { Slog.i(TAG, "Device does not support HDMI-CEC."); } mMhlController = HdmiMhlController.create(mIoThread.getLooper(), mHandler); mMhlController = HdmiMhlController.create(this); if (mMhlController == null) { Slog.i(TAG, "Device does not support MHL-control."); } } /** * Returns {@link Looper} for IO operation. * * <p>Declared as package-private. */ Looper getIoLooper() { return mIoThread.getLooper(); } /** * Returns {@link Looper} of main thread. Use this {@link Looper} instance * for tasks that are running on main service thread. * * <p>Declared as package-private. */ Looper getServiceLooper() { return Looper.myLooper(); } } services/core/jni/com_android_server_hdmi_HdmiCecController.cpp +125 −9 Original line number Diff line number Diff line Loading @@ -19,57 +19,173 @@ #define LOG_NDEBUG 1 #include "JNIHelp.h" #include "ScopedPrimitiveArray.h" #include <string> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> #include <hardware/hdmi_cec.h> #include <sys/param.h> namespace android { static struct { jmethodID handleMessage; jmethodID handleIncomingCecCommand; jmethodID handleHotplug; } gHdmiCecControllerClassInfo; class HdmiCecController { public: HdmiCecController(jobject callbacksObj); HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj); void init(); // Send message to other device. Note that it runs in IO thread. int sendMessage(const cec_message_t& message); private: // Propagate the message up to Java layer. void propagateCecCommand(const cec_message_t& message); void propagateHotplugEvent(const hotplug_event_t& event); 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; }; HdmiCecController::HdmiCecController(jobject callbacksObj) : HdmiCecController::HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj) : mDevice(device), mCallbacksObj(callbacksObj) { } void HdmiCecController::init() { mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this); } 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); env->CallVoidMethod(mCallbacksObj, gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr, dstAddr, body); env->DeleteLocalRef(body); checkAndClearExceptionFromCallback(env, __FUNCTION__); } void HdmiCecController::propagateHotplugEvent(const hotplug_event_t& event) { JNIEnv* env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod(mCallbacksObj, gHdmiCecControllerClassInfo.handleHotplug, event.connected); checkAndClearExceptionFromCallback(env, __FUNCTION__); } int HdmiCecController::sendMessage(const cec_message_t& message) { // TODO: propagate send_message's return value. return mDevice->send_message(mDevice, &message); } // 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) { HdmiCecController* handler = static_cast<HdmiCecController*>(arg); if (handler == NULL) { HdmiCecController* controller = static_cast<HdmiCecController*>(arg); if (controller == NULL) { return; } // TODO: propagate message to Java layer. 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; } } //------------------------------------------------------------------------------ #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ 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: initialize hal and pass it to controller if ready. 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", 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); if (err != 0) { ALOGE("Error opening hardware module: %d", err); return 0; } HdmiCecController* controller = new HdmiCecController( reinterpret_cast<hdmi_cec_device*>(device), env->NewGlobalRef(callbacksObj)); controller->init(); GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz, "handleIncomingCecCommand", "(II[B)V"); GET_METHOD_ID(gHdmiCecControllerClassInfo.handleHotplug, clazz, "handleHotplug", "(Z)V"); return reinterpret_cast<jlong>(controller); } static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr, jint srcAddr, jint dstAddr, jbyteArray body) { cec_message_t message; message.initiator = static_cast<cec_logical_address_t>(srcAddr); message.destination = static_cast<cec_logical_address_t>(dstAddr); jsize len = env->GetArrayLength(body); message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH); ScopedByteArrayRO bodyPtr(env, body); std::memcpy(message.body, bodyPtr.get(), len); HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); return controller->sendMessage(message); } static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;)J", (void *) nativeInit }, { "nativeSendCommand", "(JII[B)I", (void *) nativeSendCecCommand }, }; #define CLASS_PATH "com/android/server/hdmi/HdmiCecController" Loading Loading
services/core/java/com/android/server/hdmi/HdmiCecController.java +115 −17 Original line number Diff line number Diff line Loading @@ -16,9 +16,14 @@ package com.android.server.hdmi; import android.hardware.hdmi.HdmiCec; import android.hardware.hdmi.HdmiCecMessage; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Slog; import java.util.Arrays; /** * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command Loading @@ -32,12 +37,27 @@ import android.os.Message; class HdmiCecController { private static final String TAG = "HdmiCecController"; // A message to pass cec send command to IO looper. private static final int MSG_SEND_CEC_COMMAND = 1; // Message types to handle incoming message in main service looper. private final static int MSG_RECEIVE_CEC_COMMAND = 1; // TODO: move these values to HdmiCec.java once make it internal constant class. // CEC's ABORT reason values. private static final int ABORT_UNRECOGNIZED_MODE = 0; private static final int ABORT_NOT_IN_CORRECT_MODE = 1; private static final int ABORT_CANNOT_PROVIDE_SOURCE = 2; private static final int ABORT_INVALID_OPERAND = 3; private static final int ABORT_REFUSED = 4; private static final int ABORT_UNABLE_TO_DETERMINE = 5; // Handler instance to process synchronous I/O (mainly send) message. private Handler mIoHandler; // Handler instance to process various messages coming from other CEC // device or issued by internal state change. private Handler mMessageHandler; private Handler mControlHandler; // Stores the pointer to the native implementation of the service that // interacts with HAL. Loading @@ -52,14 +72,12 @@ class HdmiCecController { * inner device or has no device it will return {@code null}. * * <p>Declared as package-private, accessed by {@link HdmiControlService} only. * * @param ioLooper a Looper instance to handle IO (mainly send message) operation. * @param messageHandler a message handler that processes a message coming from other * CEC compatible device or callback of internal state change. * @param service {@link HdmiControlService} instance used to create internal handler * and to pass callback for incoming message or event. * @return {@link HdmiCecController} if device is initialized successfully. Otherwise, * returns {@code null}. */ static HdmiCecController create(Looper ioLooper, Handler messageHandler) { static HdmiCecController create(HdmiControlService service) { HdmiCecController handler = new HdmiCecController(); long nativePtr = nativeInit(handler); if (nativePtr == 0L) { Loading @@ -67,28 +85,108 @@ class HdmiCecController { return null; } handler.init(ioLooper, messageHandler, nativePtr); handler.init(service, nativePtr); return handler; } private void init(Looper ioLooper, Handler messageHandler, long nativePtr) { mIoHandler = new Handler(ioLooper) { 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; } 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; default: Slog.w(TAG, "Unsupported CEC Io request:" + msg.what); break; } } } private final class ControlHandler extends Handler { private ControlHandler(Looper looper) { super(looper); } @Override public void handleMessage(Message msg) { // TODO: Call native sendMessage. switch (msg.what) { case MSG_RECEIVE_CEC_COMMAND: // TODO: delegate it to HdmiControl service. onReceiveCommand((HdmiCecMessage) msg.obj); break; default: Slog.i(TAG, "Unsupported message type:" + msg.what); break; } } } }; mMessageHandler = messageHandler; private void init(HdmiControlService service, long nativePtr) { mIoHandler = new IoHandler(service.getServiceLooper()); mControlHandler = new ControlHandler(service.getServiceLooper()); mNativePtr = nativePtr; } private void onReceiveCommand(HdmiCecMessage message) { // TODO: Handle message according to opcode type. // TODO: Use device's source address for broadcast message. int sourceAddress = message.getDestination() != HdmiCec.ADDR_BROADCAST ? message.getDestination() : 0; // Reply <Feature Abort> to initiator (source) for all requests. sendFeatureAbort(sourceAddress, message.getSource(), message.getOpcode(), ABORT_REFUSED); } private void sendFeatureAbort(int srcAddress, int destAddress, int originalOpcode, int reason) { byte[] params = new byte[2]; params[0] = (byte) originalOpcode; params[1] = (byte) reason; HdmiCecMessage cecMessage = new HdmiCecMessage(srcAddress, destAddress, HdmiCec.MESSAGE_FEATURE_ABORT, params); Message message = mIoHandler.obtainMessage(MSG_SEND_CEC_COMMAND, cecMessage); mIoHandler.sendMessage(message); } /** * 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); 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); } /** * Called by native when an HDMI-CEC message arrived. * Called by native when a hotplug event issues. */ private void handleMessage(int srcAddress, int dstAddres, int opcode, byte[] params) { // TODO: Translate message and delegate it to main message handler. private void handleHotplug(boolean connected) { // TODO: Delegate event to main message handler. } private static native long nativeInit(HdmiCecController handler); private static native int nativeSendCecCommand(long contollerPtr, int srcAddress, int dstAddress, byte[] body); }
services/core/java/com/android/server/hdmi/HdmiControlService.java +22 −12 Original line number Diff line number Diff line Loading @@ -18,9 +18,8 @@ package com.android.server.hdmi; import android.annotation.Nullable; import android.content.Context; import android.os.Handler; import android.os.HandlerThread; import android.os.Message; import android.os.Looper; import android.util.Slog; import com.android.server.SystemService; Loading @@ -37,14 +36,6 @@ public final class HdmiControlService extends SystemService { // and sparse call it shares a thread to handle IO operations. private final HandlerThread mIoThread = new HandlerThread("Hdmi Control Io Thread"); // Main handler class to handle incoming message from each controller. private final Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { // TODO: Add handler for each message type. } }; @Nullable private HdmiCecController mCecController; Loading @@ -57,14 +48,33 @@ public final class HdmiControlService extends SystemService { @Override public void onStart() { mCecController = HdmiCecController.create(mIoThread.getLooper(), mHandler); mCecController = HdmiCecController.create(this); if (mCecController == null) { Slog.i(TAG, "Device does not support HDMI-CEC."); } mMhlController = HdmiMhlController.create(mIoThread.getLooper(), mHandler); mMhlController = HdmiMhlController.create(this); if (mMhlController == null) { Slog.i(TAG, "Device does not support MHL-control."); } } /** * Returns {@link Looper} for IO operation. * * <p>Declared as package-private. */ Looper getIoLooper() { return mIoThread.getLooper(); } /** * Returns {@link Looper} of main thread. Use this {@link Looper} instance * for tasks that are running on main service thread. * * <p>Declared as package-private. */ Looper getServiceLooper() { return Looper.myLooper(); } }
services/core/jni/com_android_server_hdmi_HdmiCecController.cpp +125 −9 Original line number Diff line number Diff line Loading @@ -19,57 +19,173 @@ #define LOG_NDEBUG 1 #include "JNIHelp.h" #include "ScopedPrimitiveArray.h" #include <string> #include <android_runtime/AndroidRuntime.h> #include <android_runtime/Log.h> #include <hardware/hdmi_cec.h> #include <sys/param.h> namespace android { static struct { jmethodID handleMessage; jmethodID handleIncomingCecCommand; jmethodID handleHotplug; } gHdmiCecControllerClassInfo; class HdmiCecController { public: HdmiCecController(jobject callbacksObj); HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj); void init(); // Send message to other device. Note that it runs in IO thread. int sendMessage(const cec_message_t& message); private: // Propagate the message up to Java layer. void propagateCecCommand(const cec_message_t& message); void propagateHotplugEvent(const hotplug_event_t& event); 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; }; HdmiCecController::HdmiCecController(jobject callbacksObj) : HdmiCecController::HdmiCecController(hdmi_cec_device_t* device, jobject callbacksObj) : mDevice(device), mCallbacksObj(callbacksObj) { } void HdmiCecController::init() { mDevice->register_event_callback(mDevice, HdmiCecController::onReceived, this); } 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); env->CallVoidMethod(mCallbacksObj, gHdmiCecControllerClassInfo.handleIncomingCecCommand, srcAddr, dstAddr, body); env->DeleteLocalRef(body); checkAndClearExceptionFromCallback(env, __FUNCTION__); } void HdmiCecController::propagateHotplugEvent(const hotplug_event_t& event) { JNIEnv* env = AndroidRuntime::getJNIEnv(); env->CallVoidMethod(mCallbacksObj, gHdmiCecControllerClassInfo.handleHotplug, event.connected); checkAndClearExceptionFromCallback(env, __FUNCTION__); } int HdmiCecController::sendMessage(const cec_message_t& message) { // TODO: propagate send_message's return value. return mDevice->send_message(mDevice, &message); } // 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) { HdmiCecController* handler = static_cast<HdmiCecController*>(arg); if (handler == NULL) { HdmiCecController* controller = static_cast<HdmiCecController*>(arg); if (controller == NULL) { return; } // TODO: propagate message to Java layer. 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; } } //------------------------------------------------------------------------------ #define GET_METHOD_ID(var, clazz, methodName, methodDescriptor) \ 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: initialize hal and pass it to controller if ready. 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", 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); if (err != 0) { ALOGE("Error opening hardware module: %d", err); return 0; } HdmiCecController* controller = new HdmiCecController( reinterpret_cast<hdmi_cec_device*>(device), env->NewGlobalRef(callbacksObj)); controller->init(); GET_METHOD_ID(gHdmiCecControllerClassInfo.handleIncomingCecCommand, clazz, "handleIncomingCecCommand", "(II[B)V"); GET_METHOD_ID(gHdmiCecControllerClassInfo.handleHotplug, clazz, "handleHotplug", "(Z)V"); return reinterpret_cast<jlong>(controller); } static jint nativeSendCecCommand(JNIEnv* env, jclass clazz, jlong controllerPtr, jint srcAddr, jint dstAddr, jbyteArray body) { cec_message_t message; message.initiator = static_cast<cec_logical_address_t>(srcAddr); message.destination = static_cast<cec_logical_address_t>(dstAddr); jsize len = env->GetArrayLength(body); message.length = MIN(len, CEC_MESSAGE_BODY_MAX_LENGTH); ScopedByteArrayRO bodyPtr(env, body); std::memcpy(message.body, bodyPtr.get(), len); HdmiCecController* controller = reinterpret_cast<HdmiCecController*>(controllerPtr); return controller->sendMessage(message); } static JNINativeMethod sMethods[] = { /* name, signature, funcPtr */ { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;)J", (void *) nativeInit }, { "nativeSendCommand", "(JII[B)I", (void *) nativeSendCecCommand }, }; #define CLASS_PATH "com/android/server/hdmi/HdmiCecController" Loading