前言
上篇文章讲解到Radio创建过程
https://blog.csdn.net/xuqiang918/article/details/80065145
这篇文章继续分析下Radio在创建过程中传递的BandConfig参数获取过程
1 入口
回到函数
openRadioBandInternal中可以看到
config
在每次调用
openTuner
时候都会去获取一次当前band配置信息
------------------------------------------------------------------------------------------------------------------------------------------
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 */);
}
------------------------------------------------------------------------------------------------------------------------------------------
2.跟踪 getRadioConfig函数
------------------------------------------------------------------------------------------------------------------------------------------
/**
* Returns the proper {
@link
android.hardware.radio.RadioManager.BandConfig} for the given
* radio band. {
@code
null} is returned if the band is not suppored.
*/
@Nullable
private
RadioManager.BandConfig
getRadioConfig
(
int
selectedRadioBand) {
switch
(selectedRadioBand) {
case
RadioManager.
BAND_AM
:
return
mAmConfig
;
case
RadioManager.
BAND_FM
:
return
mFmConfig
;
//
TODO: Support BAND_FM_HD and BAND_AM_HD.
default
:
return null;
}
}
发现config来自于JAVA中保存的两个变量
mAmConfig
和
mFmConfig;
继续跟踪mAmConfig和mFmConfig变量发现他们都来自于
initialze
函数中程序第一次初始化或者resume调用
------------------------------------------------------------------------------------------------------------------------------------------
3.跟踪initialze() 函数
/**
* Connects to the {
@link
RadioManager}.
*/
private void
initialze
() {
Log.
d
(
TAG
,
" initialze ..."
)
;
mRadioManager
= (RadioManager) getSystemService(Context.RADIO_SERVICE)
;
if
(Log.
isLoggable
(
TAG
,
Log.
DEBUG
)) {
Log.
d
(
TAG
,
"initialze(); mRadioManager: "
+
mRadioManager
)
;
}
if
(
mRadioManager
==
null
) {
Log.
w
(
TAG
,
"RadioManager could not be loaded."
)
;
return;
}
int status = mRadioManager.listModules(mModules);
if
(status != RadioManager.
STATUS_OK
) {
Log.
w
(
TAG
,
"Load modules failed with status: "
+ status)
;
return;
}
if
(Log.
isLoggable
(
TAG
,
Log.
DEBUG
)) {
Log.
d
(
TAG
,
"initialze(); listModules complete: "
+
mModules
)
;
}
if
(
mModules
.size() ==
0
) {
Log.
w
(
TAG
,
"No radio modules on device."
)
;
return;
}
boolean
isDebugLoggable = Log.
isLoggable
(
TAG
,
Log.
DEBUG
)
;
// Load the possible radio bands. For now, just accept FM and AM bands.
for
(BandDescriptor band :
mModules
.get(
0
).getBands()) {
//if (isDebugLoggable) {
Log.
d
(
TAG
,
"loading band: "
+ band.toString())
;
//}
if
(
mFmDescriptor
==
null
&& band.getType() == RadioManager.
BAND_FM
) {
mFmDescriptor
= (RadioManager.FmBandDescriptor) band
;
}
if
(
mAmDescriptor
==
null
&& band.getType() == RadioManager.
BAND_AM
) {
mAmDescriptor
= (RadioManager.AmBandDescriptor) band
;
}
}
if
(
mFmDescriptor
==
null
&&
mAmDescriptor
==
null
) {
Log.
w
(
TAG
,
"No AM and FM radio bands could be loaded."
)
;
return;
}
//
TODO: Make stereo configurable depending on device.
mFmConfig
=
new
RadioManager.FmBandConfig.Builder(
mFmDescriptor
)
.setStereo(
true
)
.build()
;
mAmConfig
=
new
RadioManager.AmBandConfig.Builder(
mAmDescriptor
)
.setStereo(
true
)
.build()
;
// If there is a second tuner on the device, then set it up as the background scanner.
if
(
mModules
.size() >=
2
) {
if
(isDebugLoggable) {
Log.
d
(
TAG
,
"Second tuner detected on device; setting up background scanner"
)
;
}
}
mRadioSuccessfullyInitialized
=
true;
}
说明:最终发现他们来自
RadioManager类中的
JNI函数listModules
class
RadioManager
{
public native int
listModules(List<RadioManager.ModuleProperties> var1)
;
...
};
JNI声明:
static JNINativeMethod gMethods[] = {
{"
listModules",
"(Ljava/util/List;)I",
(void *)android_hardware_Radio_listModules},
{"isSounding",
"()Z",
(void *)android_hardware_Radio_isSounding},
};
JNI实现:
static jint
android_hardware_Radio_listModules(JNIEnv *env, jobject clazz,
jobject jModules)
{
ALOGV("%s", __FUNCTION__);
if (jModules == NULL) {
ALOGE("listModules NULL ArrayList");
return RADIO_STATUS_BAD_VALUE;
}
if (!env->IsInstanceOf(jModules, gArrayListClass)) {
ALOGE("listModules not an arraylist");
return RADIO_STATUS_BAD_VALUE;
}
unsigned int numModules = 0;
radio_properties_t *nModules = NULL;
status_t status = Radio::listModules(nModules, &numModules); //
if (status != NO_ERROR || numModules == 0) {
return (jint)status;
}
nModules = (radio_properties_t *)calloc(numModules, sizeof(radio_properties_t));
status = Radio::listModules(nModules, &numModules); // 注意前面失败后再次初始化处理
ALOGV("%s Radio::listModules status %d numModules %d", __FUNCTION__, status, numModules);
if (status != NO_ERROR) {
numModules = 0;
}
for (size_t i = 0; i < numModules; i++) {
if (nModules[i].num_bands == 0) {
continue;
}
ALOGV("%s module %zu id %d implementor %s product %s",
__FUNCTION__, i, nModules[i].handle, nModules[i].implementor,
nModules[i].product);
jobjectArray jBands = env->NewObjectArray(nModules[i].num_bands,
gRadioBandDescriptorClass, NULL);
for (size_t j = 0; j < nModules[i].num_bands; j++) {
jobject jBandDescriptor;
int jStatus =
convertBandDescriptorFromNative(env, &jBandDescriptor, &nModules[i].bands[j]);
if (jStatus != RADIO_STATUS_OK) {
continue;
}
env->SetObjectArrayElement(jBands, j, jBandDescriptor);
env->DeleteLocalRef(jBandDescriptor);
}
if (env->GetArrayLength(jBands) == 0) {
continue;
}
jstring jImplementor = env->NewStringUTF(nModules[i].implementor);
jstring jProduct = env->NewStringUTF(nModules[i].product);
jstring jVersion = env->NewStringUTF(nModules[i].version);
jstring jSerial = env->NewStringUTF(nModules[i].serial);
jobject jModule = env->NewObject(gModulePropertiesClass, gModulePropertiesCstor,
nModules[i].handle, nModules[i].class_id,
jImplementor, jProduct, jVersion, jSerial,
nModules[i].num_tuners,
nModules[i].num_audio_sources,
nModules[i].supports_capture,
jBands);
env->DeleteLocalRef(jImplementor);
env->DeleteLocalRef(jProduct);
env->DeleteLocalRef(jVersion);
env->DeleteLocalRef(jSerial);
env->DeleteLocalRef(jBands);
if (jModule == NULL) {
continue;
}
env->CallBooleanMethod(jModules, gArrayListMethods.add, jModule);
}
free(nModules);
return (jint) status;
}
------------------------------------------------------------------------------------------------------------------------------------------
4.还是熟悉的binder通信调用RadioService的
listModules
------------------------------------------------------------------------------------------------------------------------------------------
// Static methods
status_t Radio::listModules(struct radio_properties *properties,
uint32_t *numModules)
{
ALOGV("listModules()");
const sp<IRadioService> service = getRadioService();
if (service == 0) {
return NO_INIT;
}
return service->
listModules(properties, numModules);
}
------------------------------------------------------------------------------------------------------------------------------------------
5.跟踪I
RadioService(framework\av\service\radio)
的
listModules
------------------------------------------------------------------------------------------------------------------------------------------
virtual status_t
listModules(struct radio_properties *properties,
uint32_t *numModules)
{
if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
return BAD_VALUE;
}
Parcel data, reply;
data.writeInterfaceToken(IRadioService::getInterfaceDescriptor());
unsigned int numModulesReq = (properties == NULL) ? 0 : *numModules;
data.writeInt32(numModulesReq);
status_t status = remote()->transact(LIST_MODULES, data, &reply); // binder通信机制
if (status == NO_ERROR) {
status = (status_t)reply.readInt32();
*numModules = (unsigned int)reply.readInt32();
}
ALOGV("listModules() status %d got *numModules %d", status, *numModules);
if (status == NO_ERROR) {
if (numModulesReq > *numModules) {
numModulesReq = *numModules;
}
if (numModulesReq > 0) {
reply.read(properties, numModulesReq * sizeof(struct radio_properties));
}
}
return status;
}
------------------------------------------------------------------------------------------------------------------------------------------
status_t RadioService::listModules(struct radio_properties *properties,
uint32_t *numModules)
{
ALOGV("listModules");
AutoMutex lock(mServiceLock);
if (numModules == NULL || (*numModules != 0 && properties == NULL)) {
return BAD_VALUE;
}
size_t maxModules = *numModules;
*numModules =
mModules.size();
ALOGV("listModules mModules.size %d", mModules.size());
for (size_t i = 0; i < mModules.size() && i < maxModules; i++) {
properties[i] = mModules.valueAt(i)->properties();
}
return NO_ERROR;
}
最终properties来自于mModules对应的属性值
------------------------------------------------------------------------------------------------------------------------------------------
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;
}
如果config为空就会获取默认的config 逐渐又回到了
onFirstRef
() - >
convertProperties()
函数 而最终还是调用 HAL层tuner_get_configuration
()
------------------------------------------------------------------------------------------------------------------------------------------
所以我们如果想改变config参数那么直接通过tuner_set_configuration设置config就行,而这里需要注意的是RadioManager.java中BandConfig和BandDescriptor都需要修改源码增加set方法,其他接口都已经有了。这样就可以根据不同Region设置不同参数。