diff --git a/services/core/java/com/android/server/hdmi/HdmiCecController.java b/services/core/java/com/android/server/hdmi/HdmiCecController.java new file mode 100644 index 0000000000000..5f07108bc1257 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/HdmiCecController.java @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.hdmi; + +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +/** + * Manages HDMI-CEC command and behaviors. It converts user's command into CEC command + * and pass it to CEC HAL so that it sends message to other device. For incoming + * message it translates the message and delegates it to proper module. + * + *

It can be created only by {@link HdmiCecController#create} + * + *

Declared as package-private, accessed by {@link HdmiControlService} only. + */ +class HdmiCecController { + private static final String TAG = "HdmiCecController"; + + // 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; + + // Stores the pointer to the native implementation of the service that + // interacts with HAL. + private long mNativePtr; + + // Private constructor. Use HdmiCecController.create(). + private HdmiCecController() { + } + + /** + * A factory method to get {@link HdmiCecController}. If it fails to initialize + * inner device or has no device it will return {@code null}. + * + *

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. + * @return {@link HdmiCecController} if device is initialized successfully. Otherwise, + * returns {@code null}. + */ + static HdmiCecController create(Looper ioLooper, Handler messageHandler) { + HdmiCecController handler = new HdmiCecController(); + long nativePtr = nativeInit(handler); + if (nativePtr == 0L) { + handler = null; + return null; + } + + handler.init(ioLooper, messageHandler, nativePtr); + return handler; + } + + private void init(Looper ioLooper, Handler messageHandler, long nativePtr) { + mIoHandler = new Handler(ioLooper) { + @Override + public void handleMessage(Message msg) { + // TODO: Call native sendMessage. + } + }; + + mMessageHandler = messageHandler; + mNativePtr = nativePtr; + } + + /** + * Called by native when an HDMI-CEC message arrived. + */ + private void handleMessage(int srcAddress, int dstAddres, int opcode, byte[] params) { + // TODO: Translate message and delegate it to main message handler. + } + + private static native long nativeInit(HdmiCecController handler); +} diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java new file mode 100644 index 0000000000000..56c5b498d0260 --- /dev/null +++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +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.util.Slog; + +import com.android.server.SystemService; + +/** + * Provides a service for sending and processing HDMI control messages, + * HDMI-CEC and MHL control command, and providing the information on both standard. + */ +public final class HdmiControlService extends SystemService { + private static final String TAG = "HdmiControlService"; + + // 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. + 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; + + @Nullable + private HdmiMhlController mMhlController; + + public HdmiControlService(Context context) { + super(context); + } + + @Override + public void onStart() { + mCecController = HdmiCecController.create(mIoThread.getLooper(), mHandler); + if (mCecController == null) { + Slog.i(TAG, "Device does not support HDMI-CEC."); + } + + mMhlController = HdmiMhlController.create(mIoThread.getLooper(), mHandler); + if (mMhlController == null) { + Slog.i(TAG, "Device does not support MHL-control."); + } + } +} diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk index 1b3887c6585b9..51583a5e7452c 100644 --- a/services/core/jni/Android.mk +++ b/services/core/jni/Android.mk @@ -11,7 +11,9 @@ LOCAL_SRC_FILES += \ $(LOCAL_REL_DIR)/com_android_server_connectivity_Vpn.cpp \ $(LOCAL_REL_DIR)/com_android_server_ConsumerIrService.cpp \ $(LOCAL_REL_DIR)/com_android_server_dreams_McuHal.cpp \ + $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecController.cpp \ $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiCecService.cpp \ + $(LOCAL_REL_DIR)/com_android_server_hdmi_HdmiMhlController.cpp \ $(LOCAL_REL_DIR)/com_android_server_input_InputApplicationHandle.cpp \ $(LOCAL_REL_DIR)/com_android_server_input_InputManagerService.cpp \ $(LOCAL_REL_DIR)/com_android_server_input_InputWindowHandle.cpp \ diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp new file mode 100644 index 0000000000000..f3e8f3c26ba0e --- /dev/null +++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2014 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "HdmiCecControllerJni" + +#define LOG_NDEBUG 1 + +#include "JNIHelp.h" + +#include +#include +#include + +namespace android { + +static struct { + jmethodID handleMessage; +} gHdmiCecControllerClassInfo; + + +class HdmiCecController { +public: + HdmiCecController(jobject callbacksObj); + +private: + static void onReceived(const hdmi_event_t* event, void* arg); + + jobject mCallbacksObj; +}; + +HdmiCecController::HdmiCecController(jobject callbacksObj) : + mCallbacksObj(callbacksObj) { +} + +// static +void HdmiCecController::onReceived(const hdmi_event_t* event, void* arg) { + HdmiCecController* handler = static_cast(arg); + if (handler == NULL) { + return; + } + + // TODO: propagate message to Java layer. +} + + +//------------------------------------------------------------------------------ +static jlong nativeInit(JNIEnv* env, jclass clazz, jobject callbacksObj) { + // TODO: initialize hal and pass it to controller if ready. + + HdmiCecController* controller = new HdmiCecController( + env->NewGlobalRef(callbacksObj)); + + return reinterpret_cast(controller); +} + +static JNINativeMethod sMethods[] = { + /* name, signature, funcPtr */ + { "nativeInit", "(Lcom/android/server/hdmi/HdmiCecController;)J", + (void *) nativeInit }, +}; + +#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)); + LOG_FATAL_IF(res < 0, "Unable to register native methods."); + return 0; +} + +} /* namespace android */ diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp index bf9f7f4361274..1feb325c0b5e6 100644 --- a/services/core/jni/onload.cpp +++ b/services/core/jni/onload.cpp @@ -38,7 +38,9 @@ int register_android_server_location_GpsLocationProvider(JNIEnv* env); int register_android_server_location_FlpHardwareProvider(JNIEnv* env); int register_android_server_connectivity_Vpn(JNIEnv* env); int register_android_server_dreams_McuHal(JNIEnv* env); +int register_android_server_hdmi_HdmiCecController(JNIEnv* env); int register_android_server_hdmi_HdmiCecService(JNIEnv* env); +int register_android_server_hdmi_HdmiMhlController(JNIEnv* env); }; using namespace android; @@ -72,7 +74,10 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved) register_android_server_ConsumerIrService(env); register_android_server_dreams_McuHal(env); register_android_server_BatteryStatsService(env); + register_android_server_hdmi_HdmiCecController(env); + // TODO: remove this once replaces HdmiCecService with HdmiControlService. register_android_server_hdmi_HdmiCecService(env); + register_android_server_hdmi_HdmiMhlController(env); return JNI_VERSION_1_4; } diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java index f08d69f3b825b..259a6d355212e 100644 --- a/services/java/com/android/server/SystemServer.java +++ b/services/java/com/android/server/SystemServer.java @@ -61,6 +61,7 @@ import com.android.server.clipboard.ClipboardService; import com.android.server.content.ContentService; import com.android.server.display.DisplayManagerService; import com.android.server.dreams.DreamManagerService; +import com.android.server.hdmi.HdmiControlService; import com.android.server.input.InputManagerService; import com.android.server.lights.LightsManager; import com.android.server.lights.LightsService; @@ -918,6 +919,12 @@ public final class SystemServer { reportWtf("starting HdmiCec Service", e); } + try { + mSystemServiceManager.startService(HdmiControlService.class); + } catch (Throwable e) { + reportWtf("starting HdmiControlService", e); + } + try { Slog.i(TAG, "TvInputManagerService"); mSystemServiceManager.startService(TvInputManagerService.class);