From c08a08e32791470d037f6b06d38fa31c7d0260ee Mon Sep 17 00:00:00 2001 From: Kensuke Miyagi Date: Wed, 8 Dec 2021 00:16:58 -0800 Subject: [PATCH] Enable Frontend callback for sharee. Bug: 209873032 Test: cts.TunerTest#testShareFrontendFromTuner Change-Id: Iffd4cb5070e65fb298006d9813ce1a5b5c069a5b --- media/java/android/media/tv/tuner/Tuner.java | 61 +++++++--- media/jni/android_media_tv_Tuner.cpp | 119 +++++++++++++++---- media/jni/android_media_tv_Tuner.h | 16 ++- 3 files changed, 156 insertions(+), 40 deletions(-) diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 94de7fa17ae7c..255b391b22592 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -285,7 +285,7 @@ public class Tuner implements AutoCloseable { @Nullable private FrontendInfo mFrontendInfo; private Integer mFrontendHandle; - private Boolean mIsSharedFrontend = false; + private Tuner mFeOwnerTuner = null; private int mFrontendType = FrontendSettings.TYPE_UNDEFINED; private int mUserId; private Lnb mLnb; @@ -442,11 +442,10 @@ public class Tuner implements AutoCloseable { mFrontendLock.lock(); try { mTunerResourceManager.shareFrontend(mClientId, tuner.mClientId); - synchronized (mIsSharedFrontend) { - mFrontendHandle = tuner.mFrontendHandle; - mFrontend = tuner.mFrontend; - mIsSharedFrontend = true; - } + mFeOwnerTuner = tuner; + mFeOwnerTuner.registerFrontendCallbackListener(this); + mFrontendHandle = mFeOwnerTuner.mFrontendHandle; + mFrontend = mFeOwnerTuner.mFrontend; nativeShareFrontend(mFrontend.mId); } finally { releaseTRMSLock(); @@ -512,6 +511,27 @@ public class Tuner implements AutoCloseable { private long mNativeContext; // used by native jMediaTuner + /** + * Registers a tuner as a listener for frontend callbacks. + */ + private void registerFrontendCallbackListener(Tuner tuner) { + nativeRegisterFeCbListener(tuner.getNativeContext()); + } + + /** + * Unregisters a tuner as a listener for frontend callbacks. + */ + private void unregisterFrontendCallbackListener(Tuner tuner) { + nativeUnregisterFeCbListener(tuner.getNativeContext()); + } + + /** + * Returns the pointer to the associated JTuner. + */ + long getNativeContext() { + return mNativeContext; + } + /** * Releases the Tuner instance. */ @@ -526,19 +546,21 @@ public class Tuner implements AutoCloseable { } } - private void releaseAll() { + private void releaseFrontend() { mFrontendLock.lock(); try { if (mFrontendHandle != null) { - synchronized (mIsSharedFrontend) { - if (!mIsSharedFrontend) { - int res = nativeCloseFrontend(mFrontendHandle); - if (res != Tuner.RESULT_SUCCESS) { - TunerUtils.throwExceptionForResult(res, "failed to close frontend"); - } - mTunerResourceManager.releaseFrontend(mFrontendHandle, mClientId); + if (mFeOwnerTuner != null) { + // unregister self from the Frontend callback + mFeOwnerTuner.unregisterFrontendCallbackListener(this); + mFeOwnerTuner = null; + } else { + // close resource as owner + int res = nativeCloseFrontend(mFrontendHandle); + if (res != Tuner.RESULT_SUCCESS) { + TunerUtils.throwExceptionForResult(res, "failed to close frontend"); } - mIsSharedFrontend = false; + mTunerResourceManager.releaseFrontend(mFrontendHandle, mClientId); } FrameworkStatsLog .write(FrameworkStatsLog.TV_TUNER_STATE_CHANGED, mUserId, @@ -549,9 +571,14 @@ public class Tuner implements AutoCloseable { } finally { mFrontendLock.unlock(); } + } + + private void releaseAll() { + releaseFrontend(); mLnbLock.lock(); try { + // mLnb will be non-null only for owner tuner if (mLnb != null) { mLnb.close(); } @@ -641,6 +668,8 @@ public class Tuner implements AutoCloseable { */ private native Frontend nativeOpenFrontendByHandle(int handle); private native int nativeShareFrontend(int id); + private native void nativeRegisterFeCbListener(long nativeContext); + private native void nativeUnregisterFeCbListener(long nativeContext); @Result private native int nativeTune(int type, FrontendSettings settings); private native int nativeStopTune(); @@ -1276,7 +1305,7 @@ public class Tuner implements AutoCloseable { } private void onFrontendEvent(int eventType) { - Log.d(TAG, "Got event from tuning. Event type: " + eventType); + Log.d(TAG, "Got event from tuning. Event type: " + eventType + " for " + this); synchronized (mOnTuneEventLock) { if (mOnTuneEventExecutor != null && mOnTuneEventListener != null) { mOnTuneEventExecutor.execute(() -> { diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index c4dfee42c3cd8..f19f6fd5fef0d 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -947,20 +947,45 @@ FilterClientCallbackImpl::~FilterClientCallbackImpl() { } /////////////// FrontendClientCallbackImpl /////////////////////// -FrontendClientCallbackImpl::FrontendClientCallbackImpl(jweak tunerObj) : mObject(tunerObj) {} +FrontendClientCallbackImpl::FrontendClientCallbackImpl(JTuner* jtuner, jweak listener) { + ALOGV("FrontendClientCallbackImpl() with listener:%p", listener); + addCallbackListener(jtuner, listener); +} + +void FrontendClientCallbackImpl::addCallbackListener(JTuner* jtuner, jweak listener) { + JNIEnv *env = AndroidRuntime::getJNIEnv(); + jweak listenerRef = env->NewWeakGlobalRef(listener); + ALOGV("addCallbackListener() with listener:%p and ref:%p @%p", listener, listenerRef, this); + std::scoped_lock lock(mMutex); + mListenersMap[jtuner] = listenerRef; +} + +void FrontendClientCallbackImpl::removeCallbackListener(JTuner* listener) { + ALOGV("removeCallbackListener for listener:%p", listener); + JNIEnv *env = AndroidRuntime::getJNIEnv(); + std::scoped_lock lock(mMutex); + if (mListenersMap.find(listener) != mListenersMap.end() && mListenersMap[listener]) { + env->DeleteWeakGlobalRef(mListenersMap[listener]); + mListenersMap.erase(listener); + } +} void FrontendClientCallbackImpl::onEvent(FrontendEventType frontendEventType) { ALOGV("FrontendClientCallbackImpl::onEvent, type=%d", frontendEventType); JNIEnv *env = AndroidRuntime::getJNIEnv(); - jobject frontend(env->NewLocalRef(mObject)); - if (!env->IsSameObject(frontend, nullptr)) { - env->CallVoidMethod( - frontend, - gFields.onFrontendEventID, - (jint)frontendEventType); - } else { - ALOGE("FrontendClientCallbackImpl::onEvent:" - "Frontend object has been freed. Ignoring callback."); + std::scoped_lock lock(mMutex); + for (const auto& mapEntry : mListenersMap) { + ALOGV("JTuner:%p, jweak:%p", mapEntry.first, mapEntry.second); + jobject frontend(env->NewLocalRef(mapEntry.second)); + if (!env->IsSameObject(frontend, nullptr)) { + env->CallVoidMethod( + frontend, + gFields.onFrontendEventID, + (jint)frontendEventType); + } else { + ALOGW("FrontendClientCallbackImpl::onEvent:" + "Frontend object has been freed. Ignoring callback."); + } } } @@ -969,12 +994,25 @@ void FrontendClientCallbackImpl::onScanMessage( ALOGV("FrontendClientCallbackImpl::onScanMessage, type=%d", type); JNIEnv *env = AndroidRuntime::getJNIEnv(); jclass clazz = env->FindClass("android/media/tv/tuner/Tuner"); - jobject frontend(env->NewLocalRef(mObject)); - if (env->IsSameObject(frontend, nullptr)) { - ALOGE("FrontendClientCallbackImpl::onScanMessage:" - "Frontend object has been freed. Ignoring callback."); - return; + + std::scoped_lock lock(mMutex); + for (const auto& mapEntry : mListenersMap) { + jobject frontend(env->NewLocalRef(mapEntry.second)); + if (env->IsSameObject(frontend, nullptr)) { + ALOGE("FrontendClientCallbackImpl::onScanMessage:" + "Tuner object has been freed. Ignoring callback."); + continue; + } + executeOnScanMessage(env, clazz, frontend, type, message); } +} + +void FrontendClientCallbackImpl::executeOnScanMessage( + JNIEnv *env, const jclass& clazz, const jobject& frontend, + FrontendScanMessageType type, + const FrontendScanMessage& message) { + ALOGV("FrontendClientCallbackImpl::executeOnScanMessage, type=%d", type); + switch(type) { case FrontendScanMessageType::LOCKED: { if (message.get()) { @@ -1153,11 +1191,14 @@ void FrontendClientCallbackImpl::onScanMessage( } FrontendClientCallbackImpl::~FrontendClientCallbackImpl() { - JNIEnv *env = AndroidRuntime::getJNIEnv(); - if (mObject != nullptr) { - env->DeleteWeakGlobalRef(mObject); - mObject = nullptr; + JNIEnv *env = android::AndroidRuntime::getJNIEnv(); + ALOGV("~FrontendClientCallbackImpl()"); + std::scoped_lock lock(mMutex); + for (const auto& mapEntry : mListenersMap) { + ALOGV("deleteRef :%p at @ %p", mapEntry.second, this); + env->DeleteWeakGlobalRef(mapEntry.second); } + mListenersMap.clear(); } /////////////// Tuner /////////////////////// @@ -1176,6 +1217,10 @@ JTuner::JTuner(JNIEnv *env, jobject thiz) : mClass(nullptr) { mSharedFeId = (int)Constant::INVALID_FRONTEND_ID; } +jweak JTuner::getObject() { + return mObject; +} + JTuner::~JTuner() { if (mFeClient != nullptr) { mFeClient->close(); @@ -1188,6 +1233,7 @@ JTuner::~JTuner() { env->DeleteWeakGlobalRef(mObject); env->DeleteGlobalRef(mClass); mFeClient = nullptr; + mFeClientCb = nullptr; mDemuxClient = nullptr; mClass = nullptr; mObject = nullptr; @@ -1243,9 +1289,8 @@ jobject JTuner::openFrontendByHandle(int feHandle) { return nullptr; } - sp feClientCb = - new FrontendClientCallbackImpl(env->NewWeakGlobalRef(mObject)); - mFeClient->setCallback(feClientCb); + mFeClientCb = new FrontendClientCallbackImpl(this, mObject); + mFeClient->setCallback(mFeClientCb); // TODO: add more fields to frontend return env->NewObject( env->FindClass("android/media/tv/tuner/Tuner$Frontend"), @@ -1265,6 +1310,18 @@ int JTuner::shareFrontend(int feId) { return (int)Result::SUCCESS; } +void JTuner::registerFeCbListener(JTuner* jtuner) { + if (mFeClientCb != nullptr && jtuner != nullptr) { + mFeClientCb->addCallbackListener(jtuner, jtuner->getObject()); + } +} + +void JTuner::unregisterFeCbListener(JTuner* jtuner) { + if (mFeClientCb != nullptr && jtuner != nullptr) { + mFeClientCb->removeCallbackListener(jtuner); + } +} + jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendCapabilities &caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "", "(II)V"); @@ -3184,6 +3241,20 @@ static int android_media_tv_Tuner_share_frontend( return tuner->shareFrontend(id); } +static void android_media_tv_Tuner_register_fe_cb_listener( + JNIEnv *env, jobject thiz, jlong shareeJTuner) { + sp tuner = getTuner(env, thiz); + JTuner *jtuner = (JTuner *)shareeJTuner; + tuner->registerFeCbListener(jtuner); +} + +static void android_media_tv_Tuner_unregister_fe_cb_listener( + JNIEnv *env, jobject thiz, jlong shareeJTuner) { + sp tuner = getTuner(env, thiz); + JTuner *jtuner = (JTuner *)shareeJTuner; + tuner->unregisterFeCbListener(jtuner); +} + static int android_media_tv_Tuner_tune(JNIEnv *env, jobject thiz, jint type, jobject settings) { sp tuner = getTuner(env, thiz); FrontendSettings setting = getFrontendSettings(env, type, settings); @@ -4346,6 +4417,10 @@ static const JNINativeMethod gTunerMethods[] = { (void *)android_media_tv_Tuner_open_frontend_by_handle }, { "nativeShareFrontend", "(I)I", (void *)android_media_tv_Tuner_share_frontend }, + { "nativeRegisterFeCbListener", "(J)V", + (void*)android_media_tv_Tuner_register_fe_cb_listener }, + { "nativeUnregisterFeCbListener", "(J)V", + (void*)android_media_tv_Tuner_unregister_fe_cb_listener }, { "nativeTune", "(ILandroid/media/tv/tuner/frontend/FrontendSettings;)I", (void *)android_media_tv_Tuner_tune }, { "nativeStopTune", "()I", (void *)android_media_tv_Tuner_stop_tune }, diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 31d24ee13cf7d..06e249212444d 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -149,14 +149,21 @@ private: void getRestartEvent(jobjectArray& arr, const int size, const DemuxFilterEvent& event); }; +struct JTuner; struct FrontendClientCallbackImpl : public FrontendClientCallback { - FrontendClientCallbackImpl(jweak tunerObj); + FrontendClientCallbackImpl(JTuner*, jweak); ~FrontendClientCallbackImpl(); virtual void onEvent(FrontendEventType frontendEventType); virtual void onScanMessage( FrontendScanMessageType type, const FrontendScanMessage& message); - jweak mObject; + void executeOnScanMessage(JNIEnv *env, const jclass& clazz, const jobject& frontend, + FrontendScanMessageType type, + const FrontendScanMessage& message); + void addCallbackListener(JTuner*, jweak obj); + void removeCallbackListener(JTuner* jtuner); + std::unordered_map mListenersMap; + std::mutex mMutex; }; struct JTuner : public RefBase { @@ -171,6 +178,8 @@ struct JTuner : public RefBase { jobject getFrontendIds(); jobject openFrontendByHandle(int feHandle); int shareFrontend(int feId); + void registerFeCbListener(JTuner* jtuner); + void unregisterFeCbListener(JTuner* jtuner); jint closeFrontendById(int id); jobject getFrontendInfo(int id); int tune(const FrontendSettings& settings); @@ -192,6 +201,8 @@ struct JTuner : public RefBase { jint closeFrontend(); jint closeDemux(); + jweak getObject(); + protected: virtual ~JTuner(); @@ -200,6 +211,7 @@ private: jweak mObject; static sp mTunerClient; sp mFeClient; + sp mFeClientCb; int mFeId; int mSharedFeId; sp mLnbClient;