blob: 96e122d99800aa1c51f9e03347b498abea7d6d87 [file] [log] [blame]
/**
* Copyright (C) 2017 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 "radio.Tuner.jni"
#define LOG_NDEBUG 0
#include "com_android_server_radio_Tuner.h"
#include "com_android_server_radio_convert.h"
#include "com_android_server_radio_Tuner_TunerCallback.h"
#include <android/hardware/broadcastradio/1.1/IBroadcastRadioFactory.h>
#include <core_jni_helpers.h>
#include <utils/Log.h>
#include <JNIHelp.h>
namespace android {
namespace server {
namespace radio {
namespace Tuner {
using hardware::Return;
using hardware::hidl_vec;
namespace V1_0 = hardware::broadcastradio::V1_0;
namespace V1_1 = hardware::broadcastradio::V1_1;
using V1_0::BandConfig;
using V1_0::ITuner;
using V1_0::MetaData;
using V1_0::Result;
using V1_1::ITunerCallback;
using V1_1::ProgramListResult;
static Mutex gContextMutex;
static struct {
struct {
jfieldID nativeContext;
jfieldID region;
} Tuner;
} gjni;
struct TunerContext {
TunerContext() {}
sp<ITuner> mHalTuner;
sp<TunerCallback> mNativeCallback;
private:
DISALLOW_COPY_AND_ASSIGN(TunerContext);
};
static TunerContext& getNativeContext(jlong nativeContextHandle) {
auto nativeContext = reinterpret_cast<TunerContext*>(nativeContextHandle);
LOG_ALWAYS_FATAL_IF(nativeContext == nullptr, "Native context not initialized");
return *nativeContext;
}
/**
* Always lock gContextMutex when using native context.
*/
static TunerContext& getNativeContext(JNIEnv *env, jobject obj) {
return getNativeContext(env->GetLongField(obj, gjni.Tuner.nativeContext));
}
static jlong nativeInit(JNIEnv *env, jobject obj, jobject clientCallback) {
ALOGV("nativeInit()");
AutoMutex _l(gContextMutex);
auto ctx = new TunerContext();
ctx->mNativeCallback = new TunerCallback(env, obj, clientCallback);
static_assert(sizeof(jlong) >= sizeof(ctx), "jlong is smaller than a pointer");
return reinterpret_cast<jlong>(ctx);
}
static void nativeFinalize(JNIEnv *env, jobject obj, jlong nativeContext) {
ALOGV("nativeFinalize()");
AutoMutex _l(gContextMutex);
auto ctx = reinterpret_cast<TunerContext*>(nativeContext);
delete ctx;
}
void setHalTuner(JNIEnv *env, jobject obj, sp<ITuner> halTuner) {
ALOGV("setHalTuner(%p)", halTuner.get());
ALOGE_IF(halTuner == nullptr, "HAL tuner is a nullptr");
AutoMutex _l(gContextMutex);
auto& ctx = getNativeContext(env, obj);
ctx.mHalTuner = halTuner;
}
sp<ITuner> getHalTuner(jlong nativeContext) {
AutoMutex _l(gContextMutex);
auto tuner = getNativeContext(nativeContext).mHalTuner;
LOG_ALWAYS_FATAL_IF(tuner == nullptr, "HAL tuner not set");
return tuner;
}
sp<ITunerCallback> getNativeCallback(JNIEnv *env, jobject obj) {
AutoMutex _l(gContextMutex);
auto& ctx = getNativeContext(env, obj);
return ctx.mNativeCallback;
}
Region getRegion(JNIEnv *env, jobject obj) {
return static_cast<Region>(env->GetIntField(obj, gjni.Tuner.region));
}
static void nativeClose(JNIEnv *env, jobject obj, jlong nativeContext) {
AutoMutex _l(gContextMutex);
auto& ctx = getNativeContext(nativeContext);
ALOGI("Closing tuner %p", ctx.mHalTuner.get());
ctx.mNativeCallback->detach();
ctx.mHalTuner = nullptr;
ctx.mNativeCallback = nullptr;
}
static void nativeSetConfiguration(JNIEnv *env, jobject obj, jlong nativeContext, jobject config) {
ALOGV("nativeSetConfiguration()");
auto halTuner = getHalTuner(nativeContext);
Region region_unused;
BandConfig bandConfigHal = convert::BandConfigToHal(env, config, region_unused);
convert::ThrowIfFailed(env, halTuner->setConfiguration(bandConfigHal));
}
static jobject nativeGetConfiguration(JNIEnv *env, jobject obj, jlong nativeContext,
Region region) {
ALOGV("nativeSetConfiguration()");
auto halTuner = getHalTuner(nativeContext);
BandConfig halConfig;
Result halResult;
auto hidlResult = halTuner->getConfiguration([&](Result result, const BandConfig& config) {
halResult = result;
halConfig = config;
});
if (convert::ThrowIfFailed(env, hidlResult)) {
return nullptr;
}
return convert::BandConfigFromHal(env, halConfig, region).release();
}
static const JNINativeMethod gTunerMethods[] = {
{ "nativeInit", "(Landroid/hardware/radio/ITunerCallback;)J", (void*)nativeInit },
{ "nativeFinalize", "(J)V", (void*)nativeFinalize },
{ "nativeClose", "(J)V", (void*)nativeClose },
{ "nativeSetConfiguration", "(JLandroid/hardware/radio/RadioManager$BandConfig;)V",
(void*)nativeSetConfiguration },
{ "nativeGetConfiguration", "(JI)Landroid/hardware/radio/RadioManager$BandConfig;",
(void*)nativeGetConfiguration },
};
} // namespace Tuner
} // namespace radio
} // namespace server
void register_android_server_radio_Tuner(JavaVM *vm, JNIEnv *env) {
using namespace server::radio::Tuner;
register_android_server_radio_Tuner_TunerCallback(vm, env);
auto tunerClass = FindClassOrDie(env, "com/android/server/radio/Tuner");
gjni.Tuner.nativeContext = GetFieldIDOrDie(env, tunerClass, "mNativeContext", "J");
gjni.Tuner.region = GetFieldIDOrDie(env, tunerClass, "mRegion", "I");
auto res = jniRegisterNativeMethods(env, "com/android/server/radio/Tuner",
gTunerMethods, NELEM(gTunerMethods));
LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
}
} // namespace android