这篇文章主要根据代码结构从JAVA层到JNI层再到HAL层理解分析Radio的创建流程分解:
说明Radio和Tunner都是指的一个意思,后面叙述就用Radio描述。
1.JAVA层创建Radio(Tunner)
1.1RadioManager中调用openTuner:
——————————————————————————————————————————————
/**
* Opens the current radio band. Currently, this only supports FM and AM bands.
*
* @param radioBand One of {@link RadioManager#BAND_FM}, {@link RadioManager#BAND_AM},
* {@link RadioManager#BAND_FM_HD} or {@link RadioManager#BAND_AM_HD}.
* @return {@link RadioManager#STATUS_OK} if successful; otherwise,
* {@link RadioManager#STATUS_ERROR}.
*/
private int openRadioBandInternal(int radioBand) {
if (requestAudioFocus() != AudioManager.AUDIOFOCUS_REQUEST_GRANTED) {
Log.e(TAG, “openRadioBandInternal() audio focus request fail”);
return RadioManager.STATUS_ERROR;
}
//mCurrentRadioBand = radioBand;
RadioManager.BandConfig config = getRadioConfig(radioBand);
if (config == null) {
Log.w(TAG, “Cannot create config for radio band: ” + radioBand);
return RadioManager.STATUS_ERROR;
}
Log.e(“Radio”, “[RadioService] openRadioBandInternal ” + config);
if (mRadioTuner != null) {
mRadioTuner.setConfiguration(config);
} else {
mRadioTuner = mRadioManager.openTuner(mModules.get(0).getId(), config, true,
mInternalRadioTunerCallback, null /* handler */);
}
if (Log.isLoggable(TAG, Log.DEBUG)) {
Log.d(TAG, “openRadioBandInternal() STATUS_OK”);
}
// Reset the counter for exponential backoff each time the radio tuner has been successfully
// opened.
mReOpenRadioTunerCount = 0;
return RadioManager.STATUS_OK;
}
——————————————————————————————————————————————
分析:openTuner函数是作用就是创建Radio功能。其中
id就是底层设备ID ModuleProperties对应的是HAL层底层设备参数;
config就是Radio的band配置信息;
mInternalRadioTunerCallback 回调函数
——————————————————————————————————————————————
1.2 RadioTuner 中调用openTuner
——————————————————————————————————————————————
public RadioTuner openTuner(int moduleId, RadioManager.BandConfig config, boolean withAudio, Callback callback, Handler handler) {
if (callback == null) {
return null;
} else {
RadioModule module = new RadioModule(moduleId, config, withAudio, callback, handler);
if (module != null && !module.initCheck()) {
module = null;
}
return module;
}
}
——————————————————————————————————————————————
1.3 RadioModule 中真正调用JNI函数native_setup来创建
——————————————————————————————————————————————
RadioModule(int moduleId, BandConfig config, boolean withAudio, Callback callback, Handler handler) {
this.mId = moduleId;
this.mEventHandlerDelegate = new RadioModule.NativeEventHandlerDelegate(callback, handler);
this.
native_setup(new WeakReference(this), config, withAudio);
}
——————————————————————————————————————————————
2.JNI层分析
2.1 RadioModule中的 native_setup定义
——————————————————————————————————————————————
public class RadioModule extends RadioTuner {
private long mNativeContext = 0;
private int mId;
private NativeEventHandlerDelegate mEventHandlerDelegate;
RadioModule(int moduleId, RadioManager.BandConfig config, boolean withAudio,
RadioTuner.Callback callback, Handler handler) {
mId = moduleId;
mEventHandlerDelegate = new NativeEventHandlerDelegate(callback, handler);
native_setup(new WeakReference<RadioModule>(this), config, withAudio);
}
private native void
native_setup(Object module_this,
RadioManager.BandConfig config, boolean withAudio);
static JNINativeMethod gModuleMethods[] = {
{“native_setup”,
“(Ljava/lang/Object;Landroid/hardware/radio/RadioManager$BandConfig;Z)V”,
(void *)android_hardware_Radio_setup},
};
——————————————————————————————————————————————
2.2 JNI文件中声明和定义 android_hardware_Radio.cpp
2.2.1 声明
——————————————————————————————————————————————
static JNINativeMethod gModuleMethods[] = {
{“
native_setup“,
“(Ljava/lang/Object;Landroid/hardware/radio/RadioManager$BandConfig;Z)V”,
(void *)
android_hardware_Radio_setup},
…
};
——————————————————————————————————————————————
2.2.2 定义
——————————————————————————————————————————————
static void
android_hardware_Radio_setup(JNIEnv *env, jobject thiz,
jobject weak_this, jobject jConfig, jboolean withAudio)
{
ALOGV(“%s”, __FUNCTION__);
setRadio(env, thiz, 0);
sp<JNIRadioCallback> callback = new JNIRadioCallback(env, thiz, weak_this);
radio_handle_t handle = (radio_handle_t)env->GetIntField(thiz, gModuleFields.mId);
struct radio_band_config nConfig;
struct radio_band_config *configPtr = NULL;
if (jConfig != NULL) {
jint jStatus = convertBandConfigToNative(env, &nConfig, jConfig);
if (jStatus != RADIO_STATUS_OK) {
return;
}
configPtr = &nConfig;
}
sp<Radio> module =
Radio::attach(handle, configPtr, (bool)withAudio, callback);
if (module == 0) {
return;
}
setRadio(env, thiz, module);
}
其中attach函数作为JNI到HAL层的发起点
——————————————————————————————————————————————
2.2.3 Radio(framework\av\radio)中调用RadioServiceattach
——————————————————————————————————————————————
sp<Radio> Radio::attach(radio_handle_t handle,
const struct radio_band_config *config,
bool withAudio,
const sp<RadioCallback>& callback)
{
ALOGV(“attach()”);
sp<Radio> radio;
const sp<IRadioService> service = getRadioService();
if (service == 0) {
return radio;
}
radio = new Radio(handle, callback);
status_t status =
service->attach(handle, radio, config, withAudio, radio->mIRadio);
if (status == NO_ERROR && radio->mIRadio != 0) {
IInterface::asBinder(radio->mIRadio)->linkToDeath(radio);
} else {
ALOGW(“Error %d connecting to radio service”, status);
radio.clear();
}
return radio;
}
——————————————————————————————————————————————
2.2.4 RadioService(framework\av\service\radio)
——————————————————————————————————————————————
status_t RadioService::attach(radio_handle_t handle,
const sp<IRadioClient>& client,
const struct radio_band_config *config,
bool withAudio,
sp<IRadio>& radio)
{
ALOGV(“%s %d config %p withAudio %d”, __FUNCTION__, handle, config, withAudio);
AutoMutex lock(mServiceLock);
radio.clear();
if (client == 0) {
return BAD_VALUE;
}
ssize_t index = mModules.indexOfKey(handle);
if (index < 0) {
return BAD_VALUE;
}
sp<Module> module = mModules.valueAt(index);
if (config == NULL) {
config = module->getDefaultConfig(); // ①
if (config == NULL) {
return INVALID_OPERATION;
}
}
ALOGV(“%s region %d type %d”, __FUNCTION__, config->region, config->band.type);
radio = module->addClient(client, config, withAudio); // ②
if (radio == 0) {
return NO_INIT;
}
return NO_ERROR;
}
①处:获取对应国家band信息,比如最大FM值;最小FM值等。
②处:通过传入参数创建radio实例
——————————————————————————————————————————————
2.2.4.1 介绍 getDefaultConfig 中band参数的来源
const struct radio_band_config *RadioService::Module::getDefaultConfig() const
{
if (mProperties.num_bands == 0) {
return NULL;
}
return &mProperties.bands[0];
}
mProperties来自下面的设备halProperties参数
——————————————————————————————————————————————
void RadioService::onFirstRef()
{
const hw_module_t *mod;
int rc;
struct radio_hw_device *dev;
ALOGI(“%s”, __FUNCTION__);
rc = hw_get_module_by_class(RADIO_HARDWARE_MODULE_ID, RADIO_HARDWARE_MODULE_ID_FM, &mod);
if (rc != 0) {
ALOGE(“couldn’t load radio module %s.%s (%s)”,
RADIO_HARDWARE_MODULE_ID, “primary”, strerror(-rc));
return;
}
rc = radio_hw_device_open(mod, &dev);
if (rc != 0) {
ALOGE(“couldn’t open radio hw device in %s.%s (%s)”,
RADIO_HARDWARE_MODULE_ID, “primary”, strerror(-rc));
return;
}
if (dev->common.version != RADIO_DEVICE_API_VERSION_CURRENT) {
ALOGE(“wrong radio hw device version %04x”, dev->common.version);
return;
}
struct radio_hal_properties halProperties;
rc = dev->get_properties(dev, &halProperties); // 调用底层HAL函数 rdev_get_properties 获取当前设备信息,看下面HAL分析
if (rc != 0) {
ALOGE(“could not read implementation properties”);
return;
}
radio_properties_t properties;
properties.handle =
(radio_handle_t)android_atomic_inc(&mNextUniqueId);
ALOGI(“loaded default module %s, handle %d”, properties.product, properties.handle);
convertProperties(&properties, &halProperties); // 转换拷贝band信息
sp<Module> module = new Module(dev, properties);
mModules.add(properties.handle, module);
}
说明其中在convertProperties函数中就调用的各个国家的信息赋值 sKnownRegionConfigs,如下:
——————————————————————————————————————————————
/* static */
void RadioService::
convertProperties(radio_properties_t *properties,
const radio_hal_properties_t *halProperties)
{
memset(properties, 0, sizeof(struct radio_properties));
properties->class_id = halProperties->class_id;
strlcpy(properties->implementor, halProperties->implementor,
RADIO_STRING_LEN_MAX);
strlcpy(properties->product, halProperties->product,
RADIO_STRING_LEN_MAX);
strlcpy(properties->version, halProperties->version,
RADIO_STRING_LEN_MAX);
strlcpy(properties->serial, halProperties->serial,
RADIO_STRING_LEN_MAX);
properties->num_tuners = halProperties->num_tuners;
properties->num_audio_sources = halProperties->num_audio_sources;
properties->supports_capture = halProperties->supports_capture;
for (size_t i = 0; i < ARRAY_SIZE(sKnownRegionConfigs); i++) {
const radio_hal_band_config_t *band = &
sKnownRegionConfigs[i].band;
size_t j;
for (j = 0; j < halProperties->num_bands; j++) {
const radio_hal_band_config_t *halBand = &halProperties->bands[j];
size_t k;
if (band->type != halBand->type) continue;
if (band->lower_limit < halBand->lower_limit) continue;
if (band->upper_limit > halBand->upper_limit) continue;
for (k = 0; k < halBand->num_spacings; k++) {
if (band->spacings[0] == halBand->spacings[k]) break;
}
if (k == halBand->num_spacings) continue;
if (band->type == RADIO_BAND_AM) break;
if ((band->fm.deemphasis & halBand->fm.deemphasis) == 0) continue;
if (halBand->fm.rds == 0) break;
if ((band->fm.rds & halBand->fm.rds) != 0) break;
}
if (j == halProperties->num_bands) continue;
ALOGI(“convertProperties() Adding band type %d region %d”,
sKnownRegionConfigs[i].band.type , sKnownRegionConfigs[i].region);
memcpy(&properties->bands[properties->num_bands++],
&sKnownRegionConfigs[i],
sizeof(radio_band_config_t));
}
}
——————————————————————————————————————————————
3.HAL层代码调用 获取设备信息
——————————————————————————————————————————————
3.1关系代码在Radio_hw.c中,HAL层函数接口绑定如下:
void RadioService::onFirstRef()中已经看到代码
rc = dev->get_properties(dev, &halProperties);
——————————————————————————————————————————————
code:
static int rdev_open(const hw_module_t *module,
const char *name,
hw_device_t **device) {
struct stub_radio_device *rdev;
int ret;
if (strcmp(name, RADIO_HARDWARE_DEVICE) != 0) {
return -EINVAL;
}
rdev = calloc(1,
sizeof(struct stub_radio_device));
if (!rdev) {
return -ENOMEM;
}
rdev->device.common.tag = HARDWARE_DEVICE_TAG;
rdev->device.common.version =
RADIO_DEVICE_API_VERSION_1_0;
rdev->device.common.module = (struct hw_module_t *) module;
rdev->device.common.close = rdev_close;
rdev->device.get_properties = rdev_get_properties;
rdev->device.open_tuner = rdev_open_tuner;
rdev->device.close_tuner = rdev_close_tuner;
pthread_mutex_init(&rdev->lock, (const pthread_mutexattr_t *) NULL);
*device = &rdev->device.common;
return 0;
}
——————————————————————————————————————————————
3.2最终HAL层调用rdev_get_properties 获取设备信息
static int rdev_get_properties(const struct
radio_hw_device *dev,
radio_hal_properties_t *properties) {
struct stub_radio_device *rdev = (struct
stub_radio_device *)dev;
ALOGI(“%s”, __func__);
if (properties == NULL) {
return -EINVAL;
}
memcpy(properties, &hw_properties,
sizeof(radio_hal_properties_t));
return 0;
}
——————————————————————————————————————————————
3.3 hw_properties定义如下
static const radio_hal_properties_t hw_properties = {
.class_id = RADIO_CLASS_AM_FM,
.implementor = “The Android Open Source Project”,
.product = “Radio stub HAL”,
.version = “0.1”,
.serial = “0123456789”,
.num_tuners = 1,
.num_audio_sources = 1,
.supports_capture = false,
.num_bands = 2,
.bands = {
{
.type = RADIO_BAND_FM,
.antenna_connected = true,
.lower_limit = 87500,
.upper_limit = 108000,
.num_spacings = 1,
.spacings = { 100 },
.fm = {
.deemphasis = RADIO_DEEMPHASIS_50,
.stereo = true,
.rds = RADIO_RDS_NONE,
.ta = false,
.af = false,
.ea = false,
}
},
{
.type = RADIO_BAND_AM,
.antenna_connected = true,
.lower_limit = 531,
.upper_limit = 1611,
.num_spacings = 1,
.spacings = { 9 },
.am = {
.stereo = true,
}
}
}
};
该结构体定义了Radio基本信息包括band初始信息
注意此变量只会在radio设备初始化时候调用一次,如果需要更改不同国家不同band信息配置,那么需要在openTuner中传入对应国家band
配置信息即可
——————————————————————————————————————————————