本文基于安卓14源码以setParameters这个接口为例追踪其从APP到HAL层的调用流程。
APP层调用
AudioManager mAudioManager = (AudioManager)getContext().getSystemService(Context.AUDIO_SERVICE);
mAudioManager.setParameters("key-value");
==》/frameworks/base/media/java/android/media/AudioManager.java
/**
* Sets a variable number of parameter values to audio hardware.
*
* @param keyValuePairs list of parameters key value pairs in the form:
* key1=value1;key2=value2;...
*
*/
public void setParameters(String keyValuePairs) {
AudioSystem.setParameters(keyValuePairs);
}
==>/frameworks/base/media/java/android/media/AudioSystem.java
/**
* @hide
* Sets a group generic audio configuration parameters. The use of these parameters
* are platform dependent, see libaudio
*
* param keyValuePairs list of parameters key value pairs in the form:
* key1=value1;key2=value2;...
*/
@UnsupportedAppUsage
public static native int setParameters(String keyValuePairs);
AudioSystem.java中setParameters是native方法,通过JNI调用到native层。
==》/frameworks/base/core/jni/android_media_AudioSystem.cpp
android_media_AudioSystem_setParameters(JNIEnv *env, jobject thiz, jstring keyValuePairs)
{
const jchar* c_keyValuePairs = env->GetStringCritical(keyValuePairs, 0);
String8 c_keyValuePairs8;
if (keyValuePairs) {
c_keyValuePairs8 = String8(
reinterpret_cast<const char16_t*>(c_keyValuePairs),
env->GetStringLength(keyValuePairs));
env->ReleaseStringCritical(keyValuePairs, c_keyValuePairs);
}
int status = check_AudioSystem_Command(AudioSystem::setParameters(c_keyValuePairs8));
return (jint) status;
}
===》/frameworks/av/media/libaudioclient/AudioSystem.cpp
status_t AudioSystem::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs) {
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
return af->setParameters(ioHandle, keyValuePairs);
}
获取AudioFlinger的binder对象,调用AudioFlinger的setParameters方法
==》/frameworks/av/services/audioflinger/AudioFlinger.cpp
status_t AudioFlinger::setParameters(audio_io_handle_t ioHandle, const String8& keyValuePairs)
{
// check calling permissions
if (!settingsAllowed()) {
return PERMISSION_DENIED;
}
String8 filteredKeyValuePairs = keyValuePairs;
filterReservedParameters(filteredKeyValuePairs, IPCThreadState::self()->getCallingUid());
// AUDIO_IO_HANDLE_NONE means the parameters are global to the audio hardware interface
if (ioHandle == AUDIO_IO_HANDLE_NONE) {
Mutex::Autolock _l(mLock);
// result will remain NO_INIT if no audio device is present
status_t final_result = NO_INIT;
{
AutoMutex lock(mHardwareLock);
mHardwareStatus = AUDIO_HW_SET_PARAMETER;
for (size_t i = 0; i < mAudioHwDevs.size(); i++) {
sp<DeviceHalInterface> dev = mAudioHwDevs.valueAt(i)->hwDevice();
status_t result = dev->setParameters(filteredKeyValuePairs);
// return success if at least one audio device accepts the parameters as not all
// HALs are requested to support all parameters. If no audio device supports the
// requested parameters, the last error is reported.
if (final_result != NO_ERROR) {
final_result = result;
}
}
mHardwareStatus = AUDIO_HW_IDLE;
}
// disable AEC and NS if the device is a BT SCO headset supporting those pre processings
AudioParameter param = AudioParameter(filteredKeyValuePairs);
String8 value;
if (param.get(String8(AudioParameter::keyBtNrec), value) == NO_ERROR) {
bool btNrecIsOff = (value == AudioParameter::valueOff);
if (mBtNrecIsOff.exchange(btNrecIsOff) != btNrecIsOff) {
for (size_t i = 0; i < mRecordThreads.size(); i++) {
mRecordThreads.valueAt(i)->checkBtNrec();
}
}
}
String8 screenState;
if (param.get(String8(AudioParameter::keyScreenState), screenState) == NO_ERROR) {
bool isOff = (screenState == AudioParameter::valueOff);
if (isOff != (AudioFlinger::mScreenState & 1)) {
AudioFlinger::mScreenState = ((AudioFlinger::mScreenState & ~1) + 2) | isOff;
}
}
return final_result;
}
// hold a strong ref on thread in case closeOutput() or closeInput() is called
// and the thread is exited once the lock is released
sp<ThreadBase> thread;
{
Mutex::Autolock _l(mLock);
thread = checkPlaybackThread_l(ioHandle);
if (thread == 0) {
thread = checkRecordThread_l(ioHandle);
if (thread == 0) {
thread = checkMmapThread_l(ioHandle);
}
} else if (thread == primaryPlaybackThread_l()) {
// indicate output device change to all input threads for pre processing
AudioParameter param = AudioParameter(filteredKeyValuePairs);
int value;
if ((param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) &&
(value != 0)) {
broadcastParametersToRecordThreads_l(filteredKeyValuePairs);
}
}
}
if (thread != 0) {
status_t result = thread->setParameters(filteredKeyValuePairs);
forwardParametersToDownstreamPatches_l(thread->id(), filteredKeyValuePairs);
return result;
}
return BAD_VALUE;
}
如果ioHandle是AUDIO_IO_HANDLE_NONE,该参数表示音频参数操作不针对某个具体的音频流或设备句柄,而是作用于整个音频硬件接口。本文仅考虑此类情况(thread->setParameters调用过程有差异,但到HAL层的最终调用是一样的),进一步调用到DeviceHalInterface.setParameters。
DeviceHalAidl和DeviceHalHidl都继承了DeviceHalInterface方法,一个是基于AIDL,一个是基于HIDL,本文是基于安卓14的源码,用的是依然是HIDL(见FactoryHal.cpp中sAudioHALVersions 的定义,并未把AIDL放开),HIDL和AIDL的区别以及HAL的版本迭代会在后续的篇章中单独具体的说明。
//frameworks/av/media/libaudiohal/FactoryHal.cpp
/**
* Supported HAL versions, from most recent to least recent.
* This list need to keep sync with AudioHalVersionInfo.VERSIONS in
* media/java/android/media/AudioHalVersionInfo.java.
*/
static const std::array<AudioHalVersionInfo, 5> sAudioHALVersions = {
// TODO: remove this comment to get AIDL
// AudioHalVersionInfo(AudioHalVersionInfo::Type::AIDL, 1, 0),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 7, 1),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 7, 0),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 6, 0),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 5, 0),
AudioHalVersionInfo(AudioHalVersionInfo::Type::HIDL, 4, 0),
};
===》/frameworks/av/media/libaudiohal/impl/DeviceHalHidl.cpp
status_t DeviceHalHidl::setParameters(const String8& kvPairs) {
TIME_CHECK();
if (mDevice == 0) return NO_INIT;
hidl_vec<ParameterValue> hidlParams;
status_t status = parametersFromHal(kvPairs, &hidlParams);
if (status != OK) return status;
// TODO: change the API so that context and kvPairs are separated
return processReturn("setParameters",
utils::setParameters(mDevice, {} /* context */, hidlParams));
}
===》frameworks/av/media/libaudiohal/impl/ParameterUtils.h
template <class T>
Return<Result> setParameters(T& object, hidl_vec<ParameterValue> /*context*/,
hidl_vec<ParameterValue> keys) {
return object->setParameters(keys);
}
这是个模板函数,最终调用mDevice->setParameters(keys)
mDevice是sp<::android::hardware::audio::CPP_VERSION::IDevice>类型,是在DeviceHalHidl构造函数中初始化的。
+++++++++++++++++++++++++中断分割线++++++++++++++++++++++++++++++++++
我们先来看下mDevice是怎么初始化的?
在AudioFlinger 加载hw模块时会调用DevicesFactoryHal打开设备:
AudioHwDevice* AudioFlinger::loadHwModule_l(const char *name)
{
.....
sp<DeviceHalInterface> dev;
int rc = mDevicesFactoryHal->openDevice(name, &dev);
if (rc) {
return nullptr;
}
........
}
===》/frameworks/av/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp
status_t DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device) {
auto factories = copyDeviceFactories();
if (factories.empty()) return NO_INIT;
status_t status;
auto hidlId = idFromHal(name, &status);
if (status != OK) return status;
Result retval = Result::NOT_INITIALIZED;
for (const auto& factory : factories) {
Return<void> ret;
if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_PRIMARY) == 0) {
// In V7.1 it's not possible to cast IDevice back to IPrimaryDevice,
// thus openPrimaryDevice must be used.
#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
ret = factory->openPrimaryDevice_7_1(
#else
ret = factory->openPrimaryDevice(
#endif
[&](Result r,
const sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice>& result) {
retval = r;
if (retval == Result::OK) {
*device = new DeviceHalHidl(result);
}
});
} else {
#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
ret = factory->openDevice_7_1(
#else
ret = factory->openDevice(
#endif
hidlId,
[&](Result r,
const sp<::android::hardware::audio::CPP_VERSION::IDevice>& result) {
retval = r;
if (retval == Result::OK) {
*device = new DeviceHalHidl(result);
}
});
}
if (!ret.isOk()) return FAILED_TRANSACTION;
switch (retval) {
// Device was found and was initialized successfully.
case Result::OK: return OK;
// Device was found but failed to initalize.
case Result::NOT_INITIALIZED: return NO_INIT;
// Otherwise continue iterating.
default: ;
}
}
return BAD_VALUE;
}
先判断模块类型,本例中向AUDIO_HARDWARE_MODULE_ID_PRIMARY设备中设置参数;
再判断hal版本:
根据安卓14代码中Android.bp和frameworks/av/media/libaudiohal/FactoryHal.cpp中createHalService的实现,传入的是最近的hal版本,即libaudiohal用的是7.1版本,即MAJOR_VERSION = 7, MINOR_VERSION = 1
bool createHalService(const AudioHalVersionInfo& version, bool isDevice, void** rawInterface) {
const std::string libName = "libaudiohal@" + version.toVersionString() + ".so";
handle = dlopen(libName.c_str(), dlMode);
.......
}
cc_library_shared {
name: "libaudiohal@7.1",
defaults: [
"latest_android_hardware_audio_core_sounddose_ndk_shared",
"latest_android_hardware_audio_sounddose_ndk_shared",
"libaudiohal_default",
"libaudiohal_hidl_default"
],
srcs: [
":audio_core_hal_client_sources",
"EffectsFactoryHalEntry.cpp",
],
static_libs: [
"android.hardware.audio.common@7.0",
"android.hardware.audio.common@7.0-util",
"android.hardware.audio.common@7.1-enums",
"android.hardware.audio.common@7.1-util",
"android.hardware.audio.effect@7.0",
"android.hardware.audio.effect@7.0-util",
"android.hardware.audio@7.0",
"android.hardware.audio@7.1",
"android.hardware.audio@7.1-util",
"libaudiohal.effect@7.0",
],
shared_libs: [
"libbinder_ndk",
],
cflags: [
"-DMAJOR_VERSION=7",
"-DMINOR_VERSION=1",
"-DCOMMON_TYPES_MINOR_VERSION=0",
"-DCORE_TYPES_MINOR_VERSION=0",
"-include common/all-versions/VersionMacro.h",
]
}
回到DevicesFactoryHalHidl.cpp openDevice中,最终调用factory->openPrimaryDevice_7_1,然后调用DeviceHalHidl的构造函数,传入::android::hardware::audio::CPP_VERSION::IPrimaryDevice类型的result,对应DeviceHalHidl 构造函数:
DeviceHalHidl::DeviceHalHidl(
const sp<::android::hardware::audio::CPP_VERSION::IPrimaryDevice>& device)
: CoreConversionHelperHidl("DeviceHalHidl"),
#if MAJOR_VERSION <= 6 || (MAJOR_VERSION == 7 && MINOR_VERSION == 0)
mDevice(device),
#endif
mPrimaryDevice(device),
mSoundDoseWrapper(std::make_unique<DeviceHalHidl::SoundDoseWrapper>()) {
#if MAJOR_VERSION == 7 && MINOR_VERSION == 1
auto getDeviceRet = mPrimaryDevice->getDevice();
if (getDeviceRet.isOk()) {
mDevice = getDeviceRet;
} else {
ALOGE("Call to IPrimaryDevice.getDevice has failed: %s",
getDeviceRet.description().c_str());
}
#endif
}
传入的参数赋值给mPrimaryDevice,而mDevice根据mPrimaryDevice转化而来。
++++++++++++++++++++++++++中断结束+++++++++++++++++++++++
mDevice->setParameter会调用到hal层
===》hardware\interfaces\audio\core\all-versions\default\Device.cpp
Return<Result> Device::setParameters(const hidl_vec<ParameterValue>& context,
const hidl_vec<ParameterValue>& parameters) {
return setParametersImpl(context, parameters);
}
===》/hardware/interfaces/audio/core/all-versions/default/ParametersUtil.cpp
Result ParametersUtil::setParametersImpl(const hidl_vec<ParameterValue>& context,
const hidl_vec<ParameterValue>& parameters) {
AudioParameter params;
for (auto& pair : context) {
params.add(String8(pair.key.c_str()), String8(pair.value.c_str()));
}
for (size_t i = 0; i < parameters.size(); ++i) {
params.add(String8(parameters[i].key.c_str()), String8(parameters[i].value.c_str()));
}
return setParams(params);
}
Result ParametersUtil::setParams(const AudioParameter& param) {
int halStatus = halSetParameters(param.toString().string());
return util::analyzeStatus(halStatus);
}
===》继续调用到hardware\interfaces\audio\core\all-versions\default\Device.cpp的halSetParameters
int Device::halSetParameters(const char* keysAndValues) {
return mDevice->set_parameters(mDevice, keysAndValues);
}
mDevice是audio_hw_device_t*类型,在hardware/libhardware/modules/audio/audio_hw.c中定义了 adev->device.set_parameters = adev_set_parameters;
而adev_set_parameters具体的实现是由第三方厂商实现的,一般在hardware/厂商/audio目录下。
至此,setParameters从APP到HAL的调用流程分析完成。