Android Hal 啟動過程--以 broadcastradio hal2.0 為例
Android Hal 啟動過程--以 broadcastradio hal2.0 為例
概述
- broadcastradio hal2 的 Android 源碼位于 hardware/interfaces/broadcastradio 目錄下
- hal 進程作為服務端,調用 open/mmap/ioctol 系統接口使用 Binder IPC ,向 HIDL Service Manager 注冊服務,frameworks 會在應用軟件調用相關接口時去 HIDL 的 ServiceManager 找 hal 層的服務,如果找到,則順利調用到 hal 層,否則,報錯。
- hal 層進程注冊到 hwbinder 過程很復雜,這里只去除了如何向 Hwbinder 注冊,以及 Binder IPC 通信過程,只專注于 hal 層和 frameworks 之間接口調用,后續會繼續追蹤 hal 層的服務句柄到底是怎么傳遞到 HIDL 服務手里的。
一、拉起 hal 進程
- init 進程負責拉起 hal 進程
// system/core/init/init.cpp
static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_list) {
Parser parser = CreateParser(action_manager, service_list);
std::string bootscript = GetProperty("ro.boot.init_rc", "");
if (bootscript.empty()) {
parser.ParseConfig("/init.rc");
if (!parser.ParseConfig("/system/etc/init")) {
late_import_paths.emplace_back("/system/etc/init");
}
...
// 會將 /vendor/etc/init 文件夾所有 rc 文件都拉來
if (!parser.ParseConfig("/vendor/etc/init")) {
late_import_paths.emplace_back("/vendor/etc/init");
}
} else {
parser.ParseConfig(bootscript);
}
}
- broadcastradiohal 的 rc 文件
// hardware/interfaces/broadcastradio/2.0/default/android.hardware.broadcastradio@2.0-service.rc
// 該文件會在編譯后拷貝到 /vendor/etc/init/ 目錄下
service broadcastradio-hal2 /vendor/bin/hw/android.hardware.broadcastradio@2.0-service
class hal
user audioserver
group audio
二、hal 進程啟動
- hal 注冊服務
// hardware/interfaces/broadcastradio/2.0/default/service.cpp
int main(int /* argc */, char** /* argv */) {
BroadcastRadio broadcastRadio(gAmFmRadio);
// 向 HidlService 注冊 broadcastRadio 的服務
auto status = broadcastRadio.registerAsService();
CHECK_EQ(status, android::OK) << "Failed to register Broadcast Radio HAL implementation";
return 1; // joinRpcThreadpool shouldn't exit
}
- 注冊接口的配置文件
// manifest.xml 注冊配置文件
<hal format="hidl">
<name>android.hardware.broadcastradio</name>
<transport>hwbinder</transport>
<version>2.0</version>
<interface>
<name>IBroadcastRadio</name>
<instance>default</instance>
</interface>
</hal>
- 該文件可以在 device 目錄下和其他 hal 層接口一起設置,也可以在 hal 源碼目錄下單獨設置,如果是后者,則需要在 Android.bp 文件中指明注冊的配置文件。
- 注冊的服務名為
android.hardware.broadcastradio@2.0::IBroadcastRadio
- hal 層服務器創建
在 Android hal 中,hardware/interfaces/broadcastradio/2.0/default/ 目錄下都是接口,雖然說具體開發確實也是實現這個文件夾下的文件,但是實際上,會被 Android 使用 hidl-gen 工具生成最終的 hal 層服務器和客戶端,比如在auto status = broadcastRadio.registerAsService();注冊服務代碼就在生成的 HIDL 服務器代碼中
// out/soong/.intermediates/hardware/interfaces/broadcastradio/2.0/android.hardware.broadcastradio@2.0_genc++/gen/android/hardware/broadcastradio/2.0/BroadcastRadioAll.cpp
::android::status_t IBroadcastRadio::registerAsService(const std::string &serviceName) {
::android::hardware::details::onRegistration("android.hardware.broadcastradio@2.0", "IBroadcastRadio", serviceName);
const ::android::sp<::android::hidl::manager::V1_0::IServiceManager> sm
= ::android::hardware::defaultServiceManager();
if (sm == nullptr) {
return ::android::INVALID_OPERATION;
}
::android::hardware::Return<bool> ret = sm->add(serviceName.c_str(), this);
return ret.isOk() && ret ? ::android::OK : ::android::UNKNOWN_ERROR;
}
- HIDL broadcastradio 服務進程向 HIDL ServiceManager 注冊服務
// 該 broadcastradio 的引用和唯一標識名保存位置
// system/hwservicemanager/ServiceManager.h
struct ServiceManager : public IServiceManager, hidl_death_recipient {
...
Return<bool> add(const hidl_string& name,
const sp<IBase>& service) override;
std::map<
std::string, // package::interface e.x. "android.hidl.manager@1.0::IServiceManager"
PackageInterfaceMap
> mServiceMap;
}
// ServiceManager.cpp
Return<bool> ServiceManager::add(const hidl_string& name, const sp<IBase>& service) {
...
const HidlService *hidlService = ifaceMap.lookup(name);
if (hidlService == nullptr) {
ifaceMap.insertService(
std::make_unique<HidlService>(fqName, name, service, callingContext.pid));
} else {
hidlService->setService(service, callingContext.pid);
}
}
三、frameworks 層調用 hal 層服務
- 查看 HIDL 服務器是否有 hal 層進程接口
// frameworks/base/services/core/java/com/android/server/broadcastradio/hal2/BroadcastRadioService.java
private static @NonNull List<String> listByInterface(@NonNull String fqName) {
try {
IServiceManager manager = IServiceManager.getService();
..
List<String> list = manager.listByInterface(fqName);
return list;
} catch (RemoteException ex) {
...
}
}
- RadioModule 模塊加載 hal 層服務接口,即獲取 hal 進程對應的 broadcastradio hal 服務的引用
private RadioModule(@NonNull IBroadcastRadio service,
@NonNull RadioManager.ModuleProperties properties) {
mProperties = Objects.requireNonNull(properties);
mService = Objects.requireNonNull(service);
}
public static @Nullable RadioModule tryLoadingModule(int idx, @NonNull String fqName) {
...
return new RadioModule(service, prop);
}
- frameworks 打開與 hal 層的會話
public @NonNull TunerSession openSession(@NonNull android.hardware.radio.ITunerCallback userCb) throws RemoteException {
...
synchronized (mService) {
mService.openSession(cb, (result, session) -> {
hwSession.value = session;
halResult.value = result;
});
}
...
}
自此,radio 的 frameworks 和 hal 進程通信通道構建完成

浙公網安備 33010602011771號