HIDL 讀做 hide-l,全稱是 Hardware Interface Definition Language。它在 Android Project Treble 中被起草,在 Android 8.0 中被全面使用,其誕生目的是使 Android 能夠在不從新編譯 HAL 的狀況下對 Framework 進行 OTA 升級。
使用 HIDL 描述的 HAL 描述文件替換舊的用頭文件描述的 HAL 文件的過程稱爲 * HAL 的 binder 化(binderization)。全部運行 Android O 的設備都必須只支持 binder 化後的 HAL 模塊。
已發佈的 HIDL package包位於 Android 代碼庫的hardware/interfaces/
或vendor/<vendorName>
目錄下。使用 HDIL 描述的 HAL 接口存放在這些目錄下的.hal
文件中。好比咱們能夠在hardware/interfaces/audio/2.0/
目錄下找到部分 Audio HAL 描述文件,以下:android
Android.bp Android.mk IDevice.hal IDevicesFactory.hal IPrimaryDevice.hal IStream.hal IStreamIn.hal IStreamOutCallback.hal IStreamOut.hal types.hal
另外在frameworks/av/media/下多了個文件夾 libaudiohal :
web
Android.mk DeviceHalLocal.h DevicesFactoryHalLocal.h EffectHalHidl.h EffectsFactoryHalLocal.h StreamHalLocal.h ConversionHelperHidl.cpp DevicesFactoryHalHidl.cpp EffectBufferHalHidl.cpp EffectHalLocal.cpp HalDeathHandlerHidl.cpp ConversionHelperHidl.h DevicesFactoryHalHidl.h EffectBufferHalHidl.h EffectHalLocal.h include DeviceHalHidl.cpp DevicesFactoryHalHybrid.cpp EffectBufferHalLocal.cpp EffectsFactoryHalHidl.cpp StreamHalHidl.cpp DeviceHalHidl.h DevicesFactoryHalHybrid.h EffectBufferHalLocal.h EffectsFactoryHalHidl.h StreamHalHidl.h DeviceHalLocal.cpp DevicesFactoryHalLocal.cpp EffectHalHidl.cpp EffectsFactoryHalLocal.cpp StreamHalLocal.cpp
從文件名命名方式來看,一類是以Hidl結尾,一類是Local結尾,Local結尾的應該是兼容以前的方式,即谷歌在文檔裏描述的:安全
HIDL 旨在用於進程間通訊 (IPC)。進程之間的通訊通過 Binder 化。對於必須與進程相關聯的代碼庫,還能夠使用直通模式(在 Java 中不受支持):session
要將運行早期版本的 Android 的設備更新爲使用 Android O,您能夠將慣用的(和舊版)HAL 封裝在一個新 HIDL 接口中,該接口將在綁定式模式和同進程(直通)模式提供 HAL。這種封裝對於 HAL 和 Android 框架來講都是透明的。直通模式僅適用於 C++ 客戶端和實現。運行早期版本的 Android 的設備沒有用 Java 編寫的 HAL,所以 Java HAL 天然而然通過 Binder 化。app
直通式標頭文件:框架
編譯 .hal
文件時,除了用於 Binder 通訊的標頭以外,hidl-gen
還會生成一個額外的直通標頭文件 BsFoo.h
;此標頭定義了會被執行 dlopen
操做的函數。因爲直通式 HAL 在它們被調用的同一進程中運行,所以在大多數狀況下,直通方法由直接函數調用(同一線程)來調用。oneway
方法在各自的線程中運行,由於它們不須要等待 HAL 來處理它們(這意味着,在直通模式下使用 oneway
方法的全部 HAL 對於線程必須是安全的)。ide
若是有一個 IFoo.hal
,BsFoo.h
會封裝 HIDL 生成的方法,以提供額外的功能(例如使 oneway
事務在其餘線程中運行)。該文件相似於 BpFoo.h
,不過,所需函數是直接調用的,並未使用 Binder 傳遞調用 IPC。將來,HAL 的實現可能提供多種實現結果,例如 FooFast HAL 和 FooAccurate HAL。在這種狀況下,系統會針對每一個額外的實現結果建立一個文件(例如 PTFooFast.cpp
和 PTFooAccurate.cpp
)。函數
二、Audio Record 調用分析:ui
(1) Java層調用Android的SDK中的API實例化一個AudioRecord對象 this
-》 \android-8.0.0_r4\frameworks\av\media\libaudioclient\AudioRecord.cpp -》 AudioRecord::AudioRecord
(2) 設置相應參數
-》 mStatus = set(inputSource, sampleRate, format, channelMask, frameCount, cbf, user,
notificationFrames, false /*threadCanCallJava*/, sessionId, transferType, flags,
uid, pid, pAttributes);
(3)打開錄音接口
-》 // create the IAudioRecord
status_t status = openRecord_l(0 /*epoch*/, mOpPackageName);
(4) 獲取輸入設備屬性:
status = AudioSystem::getInputForAttr(&mAttributes, &input,
mSessionId,
// FIXME compare to AudioTrack
mClientPid,
mClientUid,
&config,
mFlags, mSelectedDeviceId, &mPortId);
其中是經過獲取audio_policy_service創建binder接口:
// establish binder interface to AudioPolicy service
const sp<IAudioPolicyService> AudioSystem::get_audio_policy_service()
(5) 調用AudioPolicyManager的接口 : \android-8.0.0_r4\frameworks\av\services\audiopolicy\managerdefault\AudioPolicyManager.cpp
aps->getInputForAttr -》 AudioPolicyManager::getInputForAttr
(6) 根據app傳下的參數獲取對應的設備類型:
device = getDeviceAndMixForInputSource(inputSource, &policyMix);
-》Engine::getDeviceForInputSource (\android-8.0.0_r4\frameworks\av\services\audiopolicy\enginedefault\src\Engine.cpp)
通常錄音軟件是:AUDIO_SOURCE_MIC ,google 語音引擎是:AUDIO_SOURCE_VOICE_RECOGNITION
再根據當前系統支持的輸入設備返回對應的錄音設備:(默認的內置mic就是 AUDIO_DEVICE_IN_BUILTIN_MIC)
if (mForceUse[AUDIO_POLICY_FORCE_FOR_RECORD] == AUDIO_POLICY_FORCE_BT_SCO && availableDeviceTypes & AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET) { device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) { device = AUDIO_DEVICE_IN_WIRED_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_HEADSET) { device = AUDIO_DEVICE_IN_USB_HEADSET; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_USB_DEVICE) { device = AUDIO_DEVICE_IN_USB_DEVICE; } else if (availableDeviceTypes & AUDIO_DEVICE_IN_BUILTIN_MIC) { device = AUDIO_DEVICE_IN_BUILTIN_MIC; }
PS:經過 dumpsys media.audio_policy 指令查看當前系統所支持的設備模塊及類型。
可經過\android-8.0.0_r4\frameworks\av\services\audiopolicy目錄裏面 audio_policy.conf或者audio_policy_configuration.xml配置設備加載,
使用.conf仍是.xml取決於frameworks/av/services/audiopolicy/Android.mk 經過宏USE_XML_AUDIO_POLICY_CONF - 1 : 使用 .xml , 0: 使用 .conf。
(7) 根據返回的device類型獲取對應錄音設備:
*input = getInputForDevice(device, address, session, uid, inputSource, config->sample_rate, config->format, config->channel_mask, flags, policyMix);
(8) 調用getInputProfile函數根據傳進來的聲音採樣率、聲音格式、通道掩碼等參數與得到的設備支持的Input Profile比較返回一個與設備Profile匹配的IOProfile-》
profile = getInputProfile(device, address, profileSamplingRate, profileFormat, profileChannelMask, profileFlags);
(9) 根據返回的profile調用初始化時加載好的client接口:
status_t status = mpClientInterface->openInput(profile->getModuleHandle(), &input, &config, &device, address, halInputSource, profileFlags);
PS: mpClientInterface是由AudioPolicyService中加載對應模塊傳遞過來:
void AudioPolicyService::onFirstRef() { { Mutex::Autolock _l(mLock); // start tone playback thread mTonePlaybackThread = new AudioCommandThread(String8("ApmTone"), this); // start audio commands thread mAudioCommandThread = new AudioCommandThread(String8("ApmAudio"), this); // start output activity command thread mOutputCommandThread = new AudioCommandThread(String8("ApmOutput"), this); mAudioPolicyClient = new AudioPolicyClient(this); mAudioPolicyManager = createAudioPolicyManager(mAudioPolicyClient); //對應的模塊加載放在AudioPolicyManager的構造函數中 } // load audio processing modules sp<AudioPolicyEffects>audioPolicyEffects = new AudioPolicyEffects(); { Mutex::Autolock _l(mLock); mAudioPolicyEffects = audioPolicyEffects; } }
AudioPolicyManager構造函數中根據宏定義判斷經過audio_policy.conf仍是audio_policy_configuration.xml解析加載對應的so:
#ifdef USE_XML_AUDIO_POLICY_CONF mVolumeCurves = new VolumeCurvesCollection(); AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices, mDefaultOutputDevice, speakerDrcEnabled, static_cast<VolumeCurvesCollection *>(mVolumeCurves)); if (deserializeAudioPolicyXmlConfig(config) != NO_ERROR) { #else mVolumeCurves = new StreamDescriptorCollection(); AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices, mDefaultOutputDevice, speakerDrcEnabled); if ((ConfigParsingUtils::loadConfig(AUDIO_POLICY_VENDOR_CONFIG_FILE, config) != NO_ERROR) && (ConfigParsingUtils::loadConfig(AUDIO_POLICY_CONFIG_FILE, config) != NO_ERROR)) { #endif
加載模塊:
mHwModules[i]->mHandle = mpClientInterface->loadHwModule(mHwModules[i]->getName()); if (mHwModules[i]->mHandle == 0) { ALOGW("could not open HW module %s", mHwModules[i]->getName()); continue; }
具體加載過程:
AudioFlinger::loadHwModule_l
-》mDevicesFactoryHal->openDevice(name, &dev);
-》DevicesFactoryHalHidl::openDevice(const char *name, sp<DeviceHalInterface> *device)
-》DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) //對應hardware/interfaces/audio/2.0/
目錄下IDevicesFactory.hal所描述接口
-》loadAudioInterface(moduleName, &halDevice);
-》DevicesFactory::loadAudioInterface(const char *if_name, audio_hw_device_t **dev)
//加載so,後面最終經過dlopen加載了/system/lib/hw/下對應的so。
rc = hw_get_module_by_class(AUDIO_HARDWARE_MODULE_ID, if_name, &mod); if (rc) { ALOGE("%s couldn't load audio hw module %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc)); goto out; }
//實際調用到了audio_hw.c中adev_open(),只會被調用一次,也就是給硬件模塊中的函數指針賦值open()。 rc = audio_hw_device_open(mod, dev); if (rc) { ALOGE("%s couldn't open audio hw device in %s.%s (%s)", __func__, AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc)); goto out; } if ((*dev)->common.version < AUDIO_DEVICE_API_VERSION_MIN) { ALOGE("%s wrong audio hw device version %04x", __func__, (*dev)->common.version); rc = -EINVAL; audio_hw_device_close(*dev); goto out; }
(10) 再回到AudioPolicyManager::getInputForDevice 中的 mpClientInterface->openInput調用流程:
AudioFlinger::openInput -》
AudioFlinger::openInput_l -》
sp<DeviceHalInterface> inHwHal = inHwDev->hwDevice();
...
inHwHal->openInputStream -》
DeviceHalHidl::openInputStream
Return<void> ret = mDevice->openInputStream( handle, hidlDevice, hidlConfig, AudioInputFlag(flags), AudioSource(source), [&](Result r, const sp<IStreamIn>& result, const AudioConfig& suggestedConfig) { retval = r; if (retval == Result::OK) { *inStream = new StreamInHalHidl(result); //audio_hw.c中adev_open_input_stream的參數stream_in在這裏建立並傳入 } HidlUtils::audioConfigToHal(suggestedConfig, config); }); return processReturn("openInputStream", ret, retval);
-》最終調用到了audio_hw.c中的:
static int adev_open_input_stream(struct audio_hw_device *dev, audio_io_handle_t handle, audio_devices_t devices, struct audio_config *config, struct audio_stream_in **stream_in, audio_input_flags_t flags, const char *address __unused, audio_source_t source )
adev_open_input_stream中對sp<StreamInHalInterface> *inStream指針的各成員進行賦值,進一步調用底層的接口獲取音頻數據。
PS:默認使用上層傳下來的config參數,也能夠手動更新stream_in的參數,好比 採樣率:stream_in->config.rate,本身實現數據獲取接口:stream_in->stream.read = my_read 等;
-end-