【Android源码分析】深入理解Radio(Tunner)创建分析

  • Post author:
  • Post category:其他



这篇文章主要根据代码结构从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

配置信息即可



——————————————————————————————————————————————



版权声明:本文为xuqiang918原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。