summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJungshik Jang <jayjang@google.com>2014-06-02 04:35:34 +0000
committerAndroid (Google) Code Review <android-gerrit@google.com>2014-06-02 04:35:35 +0000
commit37554062ed37c90aecdf7d453013e4bcae9e4c3c (patch)
tree3e9ae4ab7b231a36f6ff2f5bf421ee008744dfbf
parentdc6adf5c62064213705820a520bd1415fd8670f3 (diff)
parentc47e26ca2ff6f032c4b3a094810b1d1062bcb1ff (diff)
downloadframeworks_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
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecController.java23
-rw-r--r--services/core/java/com/android/server/hdmi/HdmiCecMessageBuilder.java15
-rw-r--r--services/core/jni/com_android_server_hdmi_HdmiCecController.cpp212
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 &lt;Feature Abort&gt; command. &lt;Feature Abort&gt; 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;
}