Extend JNI for TVMessages

Test: atest TvInputServiceTest
Bug: 278628657
Change-Id: I063b4212f93747ef3b1db2f66185a591b34f9897
This commit is contained in:
David Zhao
2023-05-07 18:47:18 -07:00
parent 3d8774d28f
commit d272a8b08c
8 changed files with 211 additions and 1 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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 {

View File

@@ -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",

View File

@@ -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));

View File

@@ -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

View File

@@ -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;

View File

@@ -23,12 +23,21 @@ typedef struct {
jmethodID deviceUnavailable;
jmethodID streamConfigsChanged;
jmethodID firstFrameCaptured;
jmethodID tvMessageReceived;
} gTvInputHalClassInfoType;
typedef struct {
jclass clazz;
} gTvStreamConfigClassInfoType;
typedef struct {
jclass clazz;
jmethodID constructor;
jmethodID putByteArray;
jmethodID putString;
jmethodID putInt;
} gBundleClassInfoType;
typedef struct {
jclass clazz;