diff options
| -rw-r--r-- | services/core/java/com/android/server/tv/TvInputHal.java | 15 | ||||
| -rwxr-xr-x | services/core/java/com/android/server/tv/TvInputHardwareManager.java | 24 | ||||
| -rw-r--r-- | services/core/java/com/android/server/tv/TvInputManagerService.java | 22 | ||||
| -rw-r--r-- | services/core/jni/Android.bp | 2 | ||||
| -rw-r--r-- | services/core/jni/com_android_server_tv_TvInputHal.cpp | 13 | ||||
| -rw-r--r-- | services/core/jni/tvinput/JTvInputHal.cpp | 86 | ||||
| -rw-r--r-- | services/core/jni/tvinput/JTvInputHal.h | 41 | ||||
| -rw-r--r-- | services/core/jni/tvinput/jstruct.h | 9 |
8 files changed, 211 insertions, 1 deletions
diff --git a/services/core/java/com/android/server/tv/TvInputHal.java b/services/core/java/com/android/server/tv/TvInputHal.java index 4bbca335b8e3..c05d148d50d8 100644 --- a/services/core/java/com/android/server/tv/TvInputHal.java +++ b/services/core/java/com/android/server/tv/TvInputHal.java @@ -19,6 +19,7 @@ package com.android.server.tv; import android.hardware.tv.input.V1_0.Constants; import android.media.tv.TvInputHardwareInfo; import android.media.tv.TvStreamConfig; +import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.MessageQueue; @@ -45,12 +46,15 @@ final class TvInputHal implements Handler.Callback { Constants.EVENT_STREAM_CONFIGURATIONS_CHANGED; public static final int EVENT_FIRST_FRAME_CAPTURED = 4; + public static final int EVENT_TV_MESSAGE = 5; + public interface Callback { void onDeviceAvailable(TvInputHardwareInfo info, TvStreamConfig[] configs); void onDeviceUnavailable(int deviceId); void onStreamConfigurationChanged(int deviceId, TvStreamConfig[] configs, int cableConnectionStatus); void onFirstFrameCaptured(int deviceId, int streamId); + void onTvMessage(int deviceId, int type, Bundle data); } private native long nativeOpen(MessageQueue queue); @@ -171,6 +175,10 @@ final class TvInputHal implements Handler.Callback { mHandler.obtainMessage(EVENT_STREAM_CONFIGURATION_CHANGED, deviceId, streamId)); } + private void tvMessageReceivedFromNative(int deviceId, int type, Bundle data) { + mHandler.obtainMessage(EVENT_TV_MESSAGE, deviceId, type, data).sendToTarget(); + } + // Handler.Callback implementation @Override @@ -221,6 +229,13 @@ final class TvInputHal implements Handler.Callback { break; } + case EVENT_TV_MESSAGE: { + int deviceId = msg.arg1; + int type = msg.arg2; + Bundle data = (Bundle) msg.obj; + mCallback.onTvMessage(deviceId, type, data); + } + default: Slog.e(TAG, "Unknown event: " + msg); return false; diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java index 077f8d527ab5..9cdceef006d9 100755 --- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java +++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java @@ -48,6 +48,7 @@ import android.media.tv.TvInputService.PriorityHintUseCaseType; import android.media.tv.TvStreamConfig; import android.media.tv.tunerresourcemanager.ResourceClientProfile; import android.media.tv.tunerresourcemanager.TunerResourceManager; +import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; @@ -59,6 +60,7 @@ import android.util.SparseArray; import android.util.SparseBooleanArray; import android.view.Surface; +import com.android.internal.os.SomeArgs; import com.android.internal.util.DumpUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.server.SystemService; @@ -264,6 +266,17 @@ class TvInputHardwareManager implements TvInputHal.Callback { } } + @Override + public void onTvMessage(int deviceId, int type, Bundle data) { + synchronized (mLock) { + SomeArgs args = SomeArgs.obtain(); + args.arg1 = mHardwareInputIdMap.get(deviceId); + args.arg2 = data; + mHandler.obtainMessage(ListenerHandler.TV_MESSAGE_RECEIVED, type, 0, args) + .sendToTarget(); + } + } + public List<TvInputHardwareInfo> getHardwareList() { synchronized (mLock) { return Collections.unmodifiableList(mHardwareList); @@ -1224,6 +1237,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { void onHdmiDeviceAdded(HdmiDeviceInfo device); void onHdmiDeviceRemoved(HdmiDeviceInfo device); void onHdmiDeviceUpdated(String inputId, HdmiDeviceInfo device); + void onTvMessage(String inputId, int type, Bundle data); } private class ListenerHandler extends Handler { @@ -1234,6 +1248,7 @@ class TvInputHardwareManager implements TvInputHal.Callback { private static final int HDMI_DEVICE_REMOVED = 5; private static final int HDMI_DEVICE_UPDATED = 6; private static final int TVINPUT_INFO_ADDED = 7; + private static final int TV_MESSAGE_RECEIVED = 8; @Override public final void handleMessage(Message msg) { @@ -1303,6 +1318,15 @@ class TvInputHardwareManager implements TvInputHal.Callback { } break; } + case TV_MESSAGE_RECEIVED: { + SomeArgs args = (SomeArgs) msg.obj; + String inputId = (String) args.arg1; + Bundle data = (Bundle) args.arg2; + int type = msg.arg1; + mListener.onTvMessage(inputId, type, data); + args.recycle(); + break; + } default: { Slog.w(TAG, "Unhandled message: " + msg); break; diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index 1f5c1cf6a959..9cfdd5fb42e7 100644 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -4146,6 +4146,28 @@ public final class TvInputManagerService extends SystemService { } } } + + @Override + public void onTvMessage(String inputId, int type, Bundle data) { + synchronized (mLock) { + UserState userState = getOrCreateUserStateLocked(mCurrentUserId); + TvInputState inputState = userState.inputMap.get(inputId); + ServiceState serviceState = userState.serviceStateMap.get(inputState.info + .getComponent()); + for (IBinder token : serviceState.sessionTokens) { + try { + SessionState sessionState = getSessionStateLocked(token, + Binder.getCallingUid(), mCurrentUserId); + if (!sessionState.isRecordingSession + && sessionState.hardwareSessionToken != null) { + sessionState.session.notifyTvMessage(type, data); + } + } catch (RemoteException e) { + Slog.e(TAG, "error in onTvMessage", e); + } + } + } + } } private static class SessionNotFoundException extends IllegalArgumentException { diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp index 2ce86add4e58..d5217c8295bd 100644 --- a/services/core/jni/Android.bp +++ b/services/core/jni/Android.bp @@ -109,6 +109,7 @@ cc_defaults { "libchrome", "libcutils", "libcrypto", + "libfmq", "liblog", "libgraphicsenv", "libgralloctypes", @@ -157,6 +158,7 @@ cc_defaults { "android.hardware.broadcastradio@1.0", "android.hardware.broadcastradio@1.1", "android.hardware.contexthub@1.0", + "android.hardware.common.fmq-V1-ndk", "android.hardware.gnss-V3-cpp", "android.hardware.gnss@1.0", "android.hardware.gnss@1.1", diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp index a8806b5ef643..1e6384031f9a 100644 --- a/services/core/jni/com_android_server_tv_TvInputHal.cpp +++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp @@ -20,6 +20,7 @@ #include "tvinput/JTvInputHal.h" +gBundleClassInfoType gBundleClassInfo; gTvInputHalClassInfoType gTvInputHalClassInfo; gTvStreamConfigClassInfoType gTvStreamConfigClassInfo; gTvStreamConfigBuilderClassInfoType gTvStreamConfigBuilderClassInfo; @@ -133,10 +134,22 @@ int register_android_server_tv_TvInputHal(JNIEnv* env) { GET_METHOD_ID( gTvInputHalClassInfo.firstFrameCaptured, clazz, "firstFrameCapturedFromNative", "(II)V"); + GET_METHOD_ID(gTvInputHalClassInfo.tvMessageReceived, clazz, "tvMessageReceivedFromNative", + "(IILandroid/os/Bundle;)V"); FIND_CLASS(gTvStreamConfigClassInfo.clazz, "android/media/tv/TvStreamConfig"); gTvStreamConfigClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigClassInfo.clazz)); + FIND_CLASS(gBundleClassInfo.clazz, "android/os/Bundle"); + gBundleClassInfo.clazz = jclass(env->NewGlobalRef(gBundleClassInfo.clazz)); + GET_METHOD_ID(gBundleClassInfo.constructor, gBundleClassInfo.clazz, "<init>", "()V"); + GET_METHOD_ID(gBundleClassInfo.putByteArray, gBundleClassInfo.clazz, "putByteArray", + "(Ljava/lang/String;[B)V"); + GET_METHOD_ID(gBundleClassInfo.putString, gBundleClassInfo.clazz, "putString", + "(Ljava/lang/String;Ljava/lang/String;)V"); + GET_METHOD_ID(gBundleClassInfo.putInt, gBundleClassInfo.clazz, "putInt", + "(Ljava/lang/String;I)V"); + FIND_CLASS(gTvStreamConfigBuilderClassInfo.clazz, "android/media/tv/TvStreamConfig$Builder"); gTvStreamConfigBuilderClassInfo.clazz = jclass(env->NewGlobalRef(gTvStreamConfigBuilderClassInfo.clazz)); diff --git a/services/core/jni/tvinput/JTvInputHal.cpp b/services/core/jni/tvinput/JTvInputHal.cpp index 6bb52174fcb2..c494044e8e18 100644 --- a/services/core/jni/tvinput/JTvInputHal.cpp +++ b/services/core/jni/tvinput/JTvInputHal.cpp @@ -275,6 +275,26 @@ void JTvInputHal::onStreamConfigurationsChanged(int deviceId, int cableConnectio cableConnectionStatus); } +void JTvInputHal::onTvMessage(int deviceId, int streamId, AidlTvMessageEventType type, + AidlTvMessage& message, signed char data[], int dataLength) { + JNIEnv* env = AndroidRuntime::getJNIEnv(); + jobject bundle = env->NewObject(gBundleClassInfo.clazz, gBundleClassInfo.constructor); + const jsize len = static_cast<jsize>(dataLength); + jbyteArray convertedData = env->NewByteArray(len); + env->SetByteArrayRegion(convertedData, 0, len, reinterpret_cast<const jbyte*>(data)); + env->CallObjectMethod(bundle, gBundleClassInfo.putString, + "android.media.tv.TvInputManager.subtype", message.subType.c_str()); + env->CallObjectMethod(bundle, gBundleClassInfo.putByteArray, + "android.media.tv.TvInputManager.raw_data", convertedData); + env->CallObjectMethod(bundle, gBundleClassInfo.putInt, + "android.media.tv.TvInputManager.group_id", message.groupId); + env->CallObjectMethod(bundle, gBundleClassInfo.putInt, + "android.media.tv.TvInputManager.stream_id", streamId); + env->CallVoidMethod(mThiz, gTvInputHalClassInfo.tvMessageReceived, deviceId, + static_cast<int>(type), bundle); + env->DeleteLocalRef(convertedData); +} + void JTvInputHal::onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded) { sp<BufferProducerThread> thread; { @@ -316,6 +336,17 @@ JTvInputHal::TvInputEventWrapper JTvInputHal::TvInputEventWrapper::createEventWr return event; } +JTvInputHal::TvMessageEventWrapper JTvInputHal::TvMessageEventWrapper::createEventWrapper( + const AidlTvMessageEvent& aidlTvMessageEvent) { + TvMessageEventWrapper event; + event.messages.insert(event.messages.begin(), std::begin(aidlTvMessageEvent.messages) + 1, + std::end(aidlTvMessageEvent.messages)); + event.streamId = aidlTvMessageEvent.streamId; + event.deviceId = aidlTvMessageEvent.messages[0].groupId; + event.type = aidlTvMessageEvent.type; + return event; +} + JTvInputHal::NotifyHandler::NotifyHandler(JTvInputHal* hal, const TvInputEventWrapper& event) { mHal = hal; mEvent = event; @@ -338,6 +369,41 @@ void JTvInputHal::NotifyHandler::handleMessage(const Message& message) { } } +JTvInputHal::NotifyTvMessageHandler::NotifyTvMessageHandler(JTvInputHal* hal, + const TvMessageEventWrapper& event) { + mHal = hal; + mEvent = event; +} + +void JTvInputHal::NotifyTvMessageHandler::handleMessage(const Message& message) { + std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>> queue = + mHal->mQueueMap[mEvent.deviceId][mEvent.streamId]; + for (AidlTvMessage item : mEvent.messages) { + if (queue == NULL || !queue->isValid() || queue->availableToRead() < item.dataLengthBytes) { + MQDescriptor<int8_t, SynchronizedReadWrite> queueDesc; + if (mHal->mTvInput->getTvMessageQueueDesc(&queueDesc, mEvent.deviceId, mEvent.streamId) + .isOk()) { + queue = std::make_shared<AidlMessageQueue<int8_t, SynchronizedReadWrite>>(queueDesc, + false); + } + if (queue == NULL || !queue->isValid() || + queue->availableToRead() < item.dataLengthBytes) { + ALOGE("Incomplete TvMessageQueue data or missing queue"); + return; + } + mHal->mQueueMap[mEvent.deviceId][mEvent.streamId] = queue; + } + signed char* buffer = new signed char[item.dataLengthBytes]; + if (queue->read(buffer, item.dataLengthBytes)) { + mHal->onTvMessage(mEvent.deviceId, mEvent.streamId, mEvent.type, item, buffer, + item.dataLengthBytes); + } else { + ALOGE("Failed to read from TvMessageQueue"); + } + delete[] buffer; + } +} + JTvInputHal::TvInputCallback::TvInputCallback(JTvInputHal* hal) { mHal = hal; } @@ -351,7 +417,15 @@ JTvInputHal::TvInputCallback::TvInputCallback(JTvInputHal* hal) { ::ndk::ScopedAStatus JTvInputHal::TvInputCallback::notifyTvMessageEvent( const AidlTvMessageEvent& event) { - // TODO: Implement this + const std::string DEVICE_ID_SUBTYPE = "device_id"; + if (sizeof(event.messages) > 0 && event.messages[0].subType == DEVICE_ID_SUBTYPE) { + mHal->mLooper + ->sendMessage(new NotifyTvMessageHandler(mHal, + TvMessageEventWrapper::createEventWrapper( + event)), + static_cast<int>(event.type)); + } + return ::ndk::ScopedAStatus::ok(); } @@ -406,4 +480,14 @@ JTvInputHal::ITvInputWrapper::ITvInputWrapper(std::shared_ptr<AidlITvInput>& aid } } +::ndk::ScopedAStatus JTvInputHal::ITvInputWrapper::getTvMessageQueueDesc( + MQDescriptor<int8_t, SynchronizedReadWrite>* out_queue, int32_t in_deviceId, + int32_t in_streamId) { + if (mIsHidl) { + return ::ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION); + } else { + return mAidlTvInput->getTvMessageQueueDesc(out_queue, in_deviceId, in_streamId); + } +} + } // namespace android diff --git a/services/core/jni/tvinput/JTvInputHal.h b/services/core/jni/tvinput/JTvInputHal.h index e29da79d62dd..e8b1c9931372 100644 --- a/services/core/jni/tvinput/JTvInputHal.h +++ b/services/core/jni/tvinput/JTvInputHal.h @@ -24,6 +24,7 @@ #include <aidl/android/media/audio/common/AudioDevice.h> #include <aidlcommonsupport/NativeHandle.h> #include <android/binder_manager.h> +#include <fmq/AidlMessageQueue.h> #include <nativehelper/JNIHelp.h> #include <utils/Errors.h> #include <utils/KeyedVector.h> @@ -40,6 +41,10 @@ #include "android_runtime/android_view_Surface.h" #include "tvinput/jstruct.h" +using ::android::AidlMessageQueue; + +using ::aidl::android::hardware::common::fmq::MQDescriptor; +using ::aidl::android::hardware::common::fmq::SynchronizedReadWrite; using ::aidl::android::hardware::tv::input::BnTvInputCallback; using ::aidl::android::hardware::tv::input::CableConnectionStatus; using ::aidl::android::hardware::tv::input::TvInputEventType; @@ -54,10 +59,16 @@ using AidlITvInput = ::aidl::android::hardware::tv::input::ITvInput; using AidlNativeHandle = ::aidl::android::hardware::common::NativeHandle; using AidlTvInputDeviceInfo = ::aidl::android::hardware::tv::input::TvInputDeviceInfo; using AidlTvInputEvent = ::aidl::android::hardware::tv::input::TvInputEvent; +using AidlTvMessage = ::aidl::android::hardware::tv::input::TvMessage; using AidlTvMessageEvent = ::aidl::android::hardware::tv::input::TvMessageEvent; using AidlTvMessageEventType = ::aidl::android::hardware::tv::input::TvMessageEventType; using AidlTvStreamConfig = ::aidl::android::hardware::tv::input::TvStreamConfig; +using AidlMessageQueueMap = std::unordered_map< + int, + std::unordered_map<int, std::shared_ptr<AidlMessageQueue<int8_t, SynchronizedReadWrite>>>>; + +extern gBundleClassInfoType gBundleClassInfo; extern gTvInputHalClassInfoType gTvInputHalClassInfo; extern gTvStreamConfigClassInfoType gTvStreamConfigClassInfo; extern gTvStreamConfigBuilderClassInfoType gTvStreamConfigBuilderClassInfo; @@ -121,6 +132,19 @@ private: TvInputDeviceInfoWrapper deviceInfo; }; + class TvMessageEventWrapper { + public: + TvMessageEventWrapper() {} + + static TvMessageEventWrapper createEventWrapper( + const AidlTvMessageEvent& aidlTvMessageEvent); + + int streamId; + int deviceId; + std::vector<AidlTvMessage> messages; + AidlTvMessageEventType type; + }; + class NotifyHandler : public MessageHandler { public: NotifyHandler(JTvInputHal* hal, const TvInputEventWrapper& event); @@ -132,6 +156,17 @@ private: JTvInputHal* mHal; }; + class NotifyTvMessageHandler : public MessageHandler { + public: + NotifyTvMessageHandler(JTvInputHal* hal, const TvMessageEventWrapper& event); + + void handleMessage(const Message& message) override; + + private: + TvMessageEventWrapper mEvent; + JTvInputHal* mHal; + }; + class TvInputCallback : public HidlITvInputCallback, public BnTvInputCallback { public: explicit TvInputCallback(JTvInputHal* hal); @@ -156,6 +191,9 @@ private: ::ndk::ScopedAStatus closeStream(int32_t in_deviceId, int32_t in_streamId); ::ndk::ScopedAStatus setTvMessageEnabled(int32_t deviceId, int32_t streamId, TvMessageEventType in_type, bool enabled); + ::ndk::ScopedAStatus getTvMessageQueueDesc( + MQDescriptor<int8_t, SynchronizedReadWrite>* out_queue, int32_t in_deviceId, + int32_t in_streamId); private: ::ndk::ScopedAStatus hidlSetCallback(const std::shared_ptr<TvInputCallback>& in_callback); @@ -178,11 +216,14 @@ private: void onDeviceUnavailable(int deviceId); void onStreamConfigurationsChanged(int deviceId, int cableConnectionStatus); void onCaptured(int deviceId, int streamId, uint32_t seq, bool succeeded); + void onTvMessage(int deviceId, int streamId, AidlTvMessageEventType type, + AidlTvMessage& message, signed char data[], int dataLength); Mutex mLock; Mutex mStreamLock; jweak mThiz; sp<Looper> mLooper; + AidlMessageQueueMap mQueueMap; KeyedVector<int, KeyedVector<int, Connection> > mConnections; diff --git a/services/core/jni/tvinput/jstruct.h b/services/core/jni/tvinput/jstruct.h index 0a4a64dbb40c..23cf4aeaffa9 100644 --- a/services/core/jni/tvinput/jstruct.h +++ b/services/core/jni/tvinput/jstruct.h @@ -23,6 +23,7 @@ typedef struct { jmethodID deviceUnavailable; jmethodID streamConfigsChanged; jmethodID firstFrameCaptured; + jmethodID tvMessageReceived; } gTvInputHalClassInfoType; typedef struct { @@ -31,6 +32,14 @@ typedef struct { typedef struct { jclass clazz; + jmethodID constructor; + jmethodID putByteArray; + jmethodID putString; + jmethodID putInt; +} gBundleClassInfoType; + +typedef struct { + jclass clazz; jmethodID constructor; jmethodID streamId; |