Android Audio HAL 服务

这篇具有很好参考价值的文章主要介绍了Android Audio HAL 服务。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在 Android 系统中,Audio HAL 服务用于管理对音频硬件的访问,AudioFlinger 通过 Audio HAL 服务访问音频硬件。这里以 Android Automotive (AAOS) 版模拟器为例,来看 Audio HAL 服务的设计、实现和访问,代码分析基于 android-12.1.0_r27 进行。

AAOS 版模拟器的 Audio HAL 服务的实现位于 device/generic/car/emulator/audio/halservice,在 android 设备中,它将以名为 android.hardware.audio.service-caremu 的进程存在,这个进程的主函数定义 (位于 device/generic/car/emulator/audio/halservice/service.cpp) 如下:

int main(int /* argc */, char* /* argv */ []) {
    // Setup HIDL Audio HAL
    configureRpcThreadpool(16, false /*callerWillJoin*/);
    android::status_t status;
    status = registerPassthroughServiceImplementation<IDevicesFactory>();
    LOG_ALWAYS_FATAL_IF(status != OK, "Error while registering audio service: %d", status);
    status = registerPassthroughServiceImplementation<IEffectsFactory>();
    LOG_ALWAYS_FATAL_IF(status != OK, "Error while registering audio effects service: %d", status);

    // Setup AudioControl HAL
    ABinderProcess_setThreadPoolMaxThreadCount(0);
    std::shared_ptr<AudioControl> audioControl = ::ndk::SharedRefBase::make<AudioControl>();

    const std::string instance = std::string() + AudioControl::descriptor + "/default";
    binder_status_t aidlStatus =
            AServiceManager_addService(audioControl->asBinder().get(), instance.c_str());
    CHECK(aidlStatus == STATUS_OK);

    ABinderProcess_joinThreadPool();
    return EXIT_FAILURE;  // should not reach
}

Audio HAL 服务由三个子服务组成,分别是 IDevicesFactoryIEffectsFactoryAudioControl,其中前两个为 hardware 服务,它们由实现于 system/hwservicemanagerhwservicemanager 管理,另外的 AudioControl 由实现于 frameworks/native/cmds/servicemanagerservicemanager 管理。

对于 AudioControl 服务的注册,相对比较容易理解,它和系统中其它各种服务,如 activity manager service、audio service 之类的,没有什么区别。这里看一下 IDevicesFactoryIEffectsFactory 服务的注册。它们都通过模板函数 registerPassthroughServiceImplementation() 注册,该函数的定义 (位于 system/libhidl/transport/include/hidl/LegacySupport.h) 如下 :

template <class Interface, class ExpectInterface = Interface>
__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
        const std::string& name = "default") {
    return registerPassthroughServiceImplementation(Interface::descriptor,
                                                    ExpectInterface::descriptor, name);
}

这个函数注册接口服务的名为 default 的版本,也就是默认版本。

这里调用的 registerPassthroughServiceImplementation() 函数定义 (位于 system/libhidl/transport/LegacySupport.cpp) 如下:

namespace details {

__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
        const std::string& interfaceName, const std::string& expectInterfaceName,
        RegisterServiceCb registerServiceCb, const std::string& serviceName) {
    sp<IBase> service =
            getRawServiceInternal(interfaceName, serviceName, true /*retry*/, true /*getStub*/);

    if (service == nullptr) {
        ALOGE("Could not get passthrough implementation for %s/%s.", interfaceName.c_str(),
              serviceName.c_str());
        return EXIT_FAILURE;
    }
    if (service->isRemote()) {
        ALOGE("Implementation of %s/%s is remote!", interfaceName.c_str(), serviceName.c_str());
        return EXIT_FAILURE;
    }

    std::string actualName;
    Return<void> result = service->interfaceDescriptor(
            [&actualName](const hidl_string& descriptor) { actualName = descriptor; });
    if (!result.isOk()) {
        ALOGE("Error retrieving interface name from %s/%s: %s", interfaceName.c_str(),
              serviceName.c_str(), result.description().c_str());
        return EXIT_FAILURE;
    }
    if (actualName != expectInterfaceName) {
        ALOGE("Implementation of %s/%s is actually %s, not a %s!", interfaceName.c_str(),
              serviceName.c_str(), actualName.c_str(), expectInterfaceName.c_str());
        return EXIT_FAILURE;
    }

    status_t status = registerServiceCb(service, serviceName);
    if (status == OK) {
        ALOGI("Registration complete for %s/%s.", interfaceName.c_str(), serviceName.c_str());
    } else {
        ALOGE("Could not register service %s/%s (%d).", interfaceName.c_str(), serviceName.c_str(),
              status);
    }

    return status;
}

}  // namespace details

__attribute__((warn_unused_result)) status_t registerPassthroughServiceImplementation(
        const std::string& interfaceName, const std::string& expectInterfaceName,
        const std::string& serviceName) {
    return details::registerPassthroughServiceImplementation(
            interfaceName, expectInterfaceName,
            [](const sp<IBase>& service, const std::string& name) {
                return details::registerAsServiceInternal(service, name);
            },
            serviceName);
}

IDevicesFactoryIEffectsFactory 在 hidl 中声明,其代码由工具自动生成,如对于 IDevicesFactory,这里的 registerPassthroughServiceImplementation() 接收到的接口名称 interfaceNameandroid.hardware.audio@6.0::IDevicesFactory,对于 IEffectsFactory,接口名称为 android.hardware.audio.effect@6.0::IEffectsFactory,服务名称 serviceName 都为 default

这里的 registerPassthroughServiceImplementation() 函数的主要执行过程可分为三步:

  1. 根据接口名称和服务名称获得原始服务对象,这主要通过 getRawServiceInternal(interfaceName, serviceName, true /*retry*/, true /*getStub*/) 完成;
  2. 对获得的服务对象做一些检查,包括是否为远程的,descriptor 的值等,android 的 HIDL 框架允许传入的服务名称和期望的服务名称不一致,大概是允许通过父服务的接口来实际访问子服务
  3. hwservicemanager 注册服务,这主要通过 registerAsServiceInternal(service, name) 完成。

getRawServiceInternal() 函数的定义 (位于 system/libhidl/transport/ServiceManagement.cpp) 如下:

sp<::android::hidl::base::V1_0::IBase> getRawServiceInternal(const std::string& descriptor,
                                                             const std::string& instance,
                                                             bool retry, bool getStub) {
    using Transport = IServiceManager1_0::Transport;
    sp<Waiter> waiter;

    sp<IServiceManager1_1> sm;
    Transport transport = Transport::EMPTY;
    if (kIsRecovery) {
        transport = Transport::PASSTHROUGH;
    } else {
        sm = defaultServiceManager1_1();
        if (sm == nullptr) {
            ALOGE("getService: defaultServiceManager() is null");
            return nullptr;
        }

        Return<Transport> transportRet = sm->getTransport(descriptor, instance);

        if (!transportRet.isOk()) {
            ALOGE("getService: defaultServiceManager()->getTransport returns %s",
                  transportRet.description().c_str());
            return nullptr;
        }
        transport = transportRet;
    }

    const bool vintfHwbinder = (transport == Transport::HWBINDER);
    const bool vintfPassthru = (transport == Transport::PASSTHROUGH);
    const bool trebleTestingOverride = isTrebleTestingOverride();
    const bool allowLegacy = !kEnforceVintfManifest || (trebleTestingOverride && isDebuggable());
    const bool vintfLegacy = (transport == Transport::EMPTY) && allowLegacy;

    if (!kEnforceVintfManifest) {
        ALOGE("getService: Potential race detected. The VINTF manifest is not being enforced. If "
              "a HAL server has a delay in starting and it is not in the manifest, it will not be "
              "retrieved. Please make sure all HALs on this device are in the VINTF manifest and "
              "enable PRODUCT_ENFORCE_VINTF_MANIFEST on this device (this is also enabled by "
              "PRODUCT_FULL_TREBLE). PRODUCT_ENFORCE_VINTF_MANIFEST will ensure that no race "
              "condition is possible here.");
        sleep(1);
    }

    for (int tries = 0; !getStub && (vintfHwbinder || vintfLegacy); tries++) {
        if (waiter == nullptr && tries > 0) {
            waiter = new Waiter(descriptor, instance, sm);
        }
        if (waiter != nullptr) {
            waiter->reset();  // don't reorder this -- see comments on reset()
        }
        Return<sp<IBase>> ret = sm->get(descriptor, instance);
        if (!ret.isOk()) {
            ALOGE("getService: defaultServiceManager()->get returns %s for %s/%s.",
                  ret.description().c_str(), descriptor.c_str(), instance.c_str());
            break;
        }
        sp<IBase> base = ret;
        if (base != nullptr) {
            Return<bool> canCastRet =
                details::canCastInterface(base.get(), descriptor.c_str(), true /* emitError */);

            if (canCastRet.isOk() && canCastRet) {
                if (waiter != nullptr) {
                    waiter->done();
                }
                return base; // still needs to be wrapped by Bp class.
            }

            if (!handleCastError(canCastRet, descriptor, instance)) break;
        }

        // In case of legacy or we were not asked to retry, don't.
        if (vintfLegacy || !retry) break;

        if (waiter != nullptr) {
            ALOGI("getService: Trying again for %s/%s...", descriptor.c_str(), instance.c_str());
            waiter->wait(true /* timeout */);
        }
    }

    if (waiter != nullptr) {
        waiter->done();
    }

    if (getStub || vintfPassthru || vintfLegacy) {
        const sp<IServiceManager1_0> pm = getPassthroughServiceManager();
        if (pm != nullptr) {
            sp<IBase> base = pm->get(descriptor, instance).withDefault(nullptr);
            if (!getStub || trebleTestingOverride) {
                base = wrapPassthrough(base);
            }
            return base;
        }
    }

    return nullptr;
}

这个函数的主要执行过程如下:

  1. 获得接口服务相应的实例的 transport 类型,当 kIsRecoverytrue 时,直接为 Transport::PASSTHROUGH,否则从 hwservicemanager 获取。HIDL 接口服务的 Transport 类型的含义后面将会看到。
  2. 在某些情况下,主要是 Transport 类型为 Transport::HWBINDER ,且非获取 stub (getStub) 的情况,尝试从 hwservicemanager 获取原始服务对象,如果成功则直接返回获得的原始服务对象;否则,继续执行;这里的从 hwservicemanager 获取原始服务对象会尝试多次。getStub 用于控制是否强制获取非包装接口服务对象,对于要注册服务的 registerPassthroughServiceImplementation() 函数来说,getStubtrue,因为它需要在当前进程中创建接口服务实例的对象然后注册给 hwservicemanager
  3. 从 passthrough service manager 获得原始服务对象,如果成功则返回获得的原始服务对象;否则,返回空值。Passthrough service manager 的定义,一定程度上阐释了 Transport::PASSTHROUGH 的含义。

hwservicemanager 中,收到获取某个接口服务的实例的 transport 类型的请求时,它会从清单文件中获取这些信息,ServiceManager::getTransport() 函数的定义 (位于 system/hwservicemanager/ServiceManager.cpp) 如下:

Return<ServiceManager::Transport> ServiceManager::getTransport(const hidl_string& fqName,
                                                               const hidl_string& name) {
    using ::android::hardware::getTransport;

    if (!mAcl.canGet(fqName, getBinderCallingContext())) {
        return Transport::EMPTY;
    }

    switch (getTransport(fqName, name)) {
        case vintf::Transport::HWBINDER:
             return Transport::HWBINDER;
        case vintf::Transport::PASSTHROUGH:
             return Transport::PASSTHROUGH;
        case vintf::Transport::EMPTY:
        default:
             return Transport::EMPTY;
    }
}

这里主要通过 ::android::hardware::getTransport() 函数获取接口服务的实例的 transport 类型,这个函数的定义 (位于 system/hwservicemanager/Vintf.cpp) 如下:

vintf::Transport getTransportFromManifest(
        const FQName &fqName, const std::string &instanceName,
        const std::shared_ptr<const vintf::HalManifest>& vm) {
    if (vm == nullptr) {
        return vintf::Transport::EMPTY;
    }
    return vm->getHidlTransport(fqName.package(), fqName.getVersion(),
                                fqName.name(), instanceName);
}

vintf::Transport getTransport(const std::string &interfaceName, const std::string &instanceName) {
    FQName fqName;

    if (!FQName::parse(interfaceName, &fqName)) {
        LOG(ERROR) << __FUNCTION__ << ": " << interfaceName
                   << " is not a valid fully-qualified name.";
        return vintf::Transport::EMPTY;
    }
    if (!fqName.hasVersion()) {
        LOG(ERROR) << __FUNCTION__ << ": " << fqName.string()
                   << " does not specify a version.";
        return vintf::Transport::EMPTY;
    }
    if (fqName.name().empty()) {
        LOG(ERROR) << __FUNCTION__ << ": " << fqName.string()
                   << " does not specify an interface name.";
        return vintf::Transport::EMPTY;
    }

    vintf::Transport tr = getTransportFromManifest(fqName, instanceName,
            vintf::VintfObject::GetFrameworkHalManifest());
    if (tr != vintf::Transport::EMPTY) {
        return tr;
    }
    tr = getTransportFromManifest(fqName, instanceName,
            vintf::VintfObject::GetDeviceHalManifest());
    if (tr != vintf::Transport::EMPTY) {
        return tr;
    }

    LOG(INFO) << __FUNCTION__ << ": Cannot find entry " << fqName.string() << "/" << instanceName
              << " in either framework or device VINTF manifest.";
    return vintf::Transport::EMPTY;
}

::android::hardware::getTransport() 从清单文件中获取接口服务的 transport 类型。它首先尝试从 Framework Hal 清单文件获取,如果失败,则尝试从 Device Hal 清单文件获取。Framework Hal 清单文件,按优先级排序包括如下这些:

1. /system/etc/vintf/manifest.xml
   + /system/etc/vintf/manifest/*.xml if they exist
   + /product/etc/vintf/manifest.xml if it exists
   + /product/etc/vintf/manifest/*.xml if they exist
2. (deprecated) /system/manifest.xml

Device Hal 清单文件,按优先级排序包括如下这些:

1. Vendor manifest + device fragments + ODM manifest (optional) + odm fragments
2. Vendor manifest + device fragments
3. ODM manifest (optional) + odm fragments
4. /vendor/manifest.xml (legacy, no fragments) where:
   A + B means unioning <hal> tags from A and B. If B declares an override, then this takes priority over A.

vintf::VintfObject 的函数的定义 (位于 system/libvintf/VintfObject.cpp) 可以看出来:

std::shared_ptr<const HalManifest> VintfObject::GetDeviceHalManifest() {
    return GetInstance()->getDeviceHalManifest();
}

std::shared_ptr<const HalManifest> VintfObject::getDeviceHalManifest() {
    return Get(__func__, &mDeviceManifest,
               std::bind(&VintfObject::fetchDeviceHalManifest, this, _1, _2));
}

std::shared_ptr<const HalManifest> VintfObject::GetFrameworkHalManifest() {
    return GetInstance()->getFrameworkHalManifest();
}

std::shared_ptr<const HalManifest> VintfObject::getFrameworkHalManifest() {
    return Get(__func__, &mFrameworkManifest,
               std::bind(&VintfObject::fetchFrameworkHalManifest, this, _1, _2));
}
 . . . . . .
// Priority for loading vendor manifest:
// 1. Vendor manifest + device fragments + ODM manifest (optional) + odm fragments
// 2. Vendor manifest + device fragments
// 3. ODM manifest (optional) + odm fragments
// 4. /vendor/manifest.xml (legacy, no fragments)
// where:
// A + B means unioning <hal> tags from A and B. If B declares an override, then this takes priority
// over A.
status_t VintfObject::fetchDeviceHalManifest(HalManifest* out, std::string* error) {
    HalManifest vendorManifest;
    status_t vendorStatus = fetchVendorHalManifest(&vendorManifest, error);
    if (vendorStatus != OK && vendorStatus != NAME_NOT_FOUND) {
        return vendorStatus;
    }

    if (vendorStatus == OK) {
        *out = std::move(vendorManifest);
        status_t fragmentStatus = addDirectoryManifests(kVendorManifestFragmentDir, out, error);
        if (fragmentStatus != OK) {
            return fragmentStatus;
        }
    }

    HalManifest odmManifest;
    status_t odmStatus = fetchOdmHalManifest(&odmManifest, error);
    if (odmStatus != OK && odmStatus != NAME_NOT_FOUND) {
        return odmStatus;
    }

    if (vendorStatus == OK) {
        if (odmStatus == OK) {
            if (!out->addAll(&odmManifest, error)) {
                if (error) {
                    error->insert(0, "Cannot add ODM manifest :");
                }
                return UNKNOWN_ERROR;
            }
        }
        return addDirectoryManifests(kOdmManifestFragmentDir, out, error);
    }

    // vendorStatus != OK, "out" is not changed.
    if (odmStatus == OK) {
        *out = std::move(odmManifest);
        return addDirectoryManifests(kOdmManifestFragmentDir, out, error);
    }

    // Use legacy /vendor/manifest.xml
    return out->fetchAllInformation(getFileSystem().get(), kVendorLegacyManifest, error);
}
 . . . . . .
// Priority:
// 1. /system/etc/vintf/manifest.xml
//    + /system/etc/vintf/manifest/*.xml if they exist
//    + /product/etc/vintf/manifest.xml if it exists
//    + /product/etc/vintf/manifest/*.xml if they exist
// 2. (deprecated) /system/manifest.xml
status_t VintfObject::fetchUnfilteredFrameworkHalManifest(HalManifest* out, std::string* error) {
    auto systemEtcStatus = fetchOneHalManifest(kSystemManifest, out, error);
    if (systemEtcStatus == OK) {
        auto dirStatus = addDirectoryManifests(kSystemManifestFragmentDir, out, error);
        if (dirStatus != OK) {
            return dirStatus;
        }

        std::vector<std::pair<const char*, const char*>> extensions{
            {kProductManifest, kProductManifestFragmentDir},
            {kSystemExtManifest, kSystemExtManifestFragmentDir},
        };
        for (auto&& [manifestPath, frags] : extensions) {
            HalManifest halManifest;
            auto status = fetchOneHalManifest(manifestPath, &halManifest, error);
            if (status != OK && status != NAME_NOT_FOUND) {
                return status;
            }
            if (status == OK) {
                if (!out->addAll(&halManifest, error)) {
                    if (error) {
                        error->insert(0, "Cannot add "s + manifestPath + ":");
                    }
                    return UNKNOWN_ERROR;
                }
            }

            auto fragmentStatus = addDirectoryManifests(frags, out, error);
            if (fragmentStatus != OK) {
                return fragmentStatus;
            }
        }

        return OK;
    } else {
        LOG(WARNING) << "Cannot fetch " << kSystemManifest << ": "
                     << (error ? *error : strerror(-systemEtcStatus));
    }

    return out->fetchAllInformation(getFileSystem().get(), kSystemLegacyManifest, error);
}

status_t VintfObject::fetchFrameworkHalManifest(HalManifest* out, std::string* error) {
    status_t status = fetchUnfilteredFrameworkHalManifest(out, error);
    if (status != OK) {
        return status;
    }
    filterHalsByDeviceManifestLevel(out);
    return OK;
}

对于 AAOS 版模拟器来说,IDevicesFactory 的清单文件为 device/generic/car/emulator/audio/driver/android.hardware.audio@6.0-impl.xml,其主要内容为:

<manifest version="1.0" type="device">
    <hal format="hidl">
        <name>android.hardware.audio</name>
        <transport>hwbinder</transport>
        <version>6.0</version>
        <interface>
            <name>IDevicesFactory</name>
            <instance>default</instance>
        </interface>
    </hal>
</manifest>

即这个接口服务的 Tansport 类型为 Transport::HWBINDER。在设备中,这个文件的路径为 /vendor/etc/vintf/manifest/android.hardware.audio@6.0-impl.xml

IEffectsFactory 的清单文件为 device/generic/car/emulator/audio/android.hardware.audio.effects@6.0.xml,其主要内容为:

<manifest version="1.0" type="device">
    <hal format="hidl">
        <name>android.hardware.audio.effect</name>
        <transport>hwbinder</transport>
        <version>6.0</version>
        <interface>
            <name>IEffectsFactory</name>
            <instance>default</instance>
        </interface>
    </hal>
</manifest>

这个接口服务的 Tansport 类型同样为 Transport::HWBINDER。在设备中,这个文件的内容将被合并之后放在 /vendor/etc/vintf/manifest.xml

对于 Audio HAL 服务,由于它需要自己创建接口服务的实例的对象,因而它将绕过从 hwservicemanager 获取接口服务的实例的对象的动作,将由 passthrough service manager 在当前进程中加载并创建,以获得原始服务对象。

PassthroughServiceManager 的定义 (位于 system/libhidl/transport/ServiceManagement.cpp) 如下:

struct PassthroughServiceManager : IServiceManager1_1 {
    static void openLibs(
        const std::string& fqName,
        const std::function<bool /* continue */ (void* /* handle */, const std::string& /* lib */,
                                                 const std::string& /* sym */)>& eachLib) {
        //fqName looks like android.hardware.foo@1.0::IFoo
        size_t idx = fqName.find("::");

        if (idx == std::string::npos ||
                idx + strlen("::") + 1 >= fqName.size()) {
            LOG(ERROR) << "Invalid interface name passthrough lookup: " << fqName;
            return;
        }

        std::string packageAndVersion = fqName.substr(0, idx);
        std::string ifaceName = fqName.substr(idx + strlen("::"));

        const std::string prefix = packageAndVersion + "-impl";
        const std::string sym = "HIDL_FETCH_" + ifaceName;
        LOG(INFO) << "Symbol " << sym;

        constexpr int dlMode = RTLD_LAZY;
        void* handle = nullptr;

        dlerror(); // clear

        static std::string halLibPathVndkSp = details::getVndkSpHwPath();
        std::vector<std::string> paths = {
            HAL_LIBRARY_PATH_ODM, HAL_LIBRARY_PATH_VENDOR, halLibPathVndkSp,
#ifndef __ANDROID_VNDK__
            HAL_LIBRARY_PATH_SYSTEM,
#endif
        };

        if (details::isTrebleTestingOverride()) {
            // Load HAL implementations that are statically linked
            handle = dlopen(nullptr, dlMode);
            if (handle == nullptr) {
                const char* error = dlerror();
                LOG(ERROR) << "Failed to dlopen self: "
                           << (error == nullptr ? "unknown error" : error);
            } else if (!eachLib(handle, "SELF", sym)) {
                return;
            }
        }

        for (const std::string& path : paths) {
            std::vector<std::string> libs = findFiles(path, prefix, ".so");

            for (const std::string &lib : libs) {
                const std::string fullPath = path + lib;

                if (kIsRecovery || path == HAL_LIBRARY_PATH_SYSTEM) {
                    handle = dlopen(fullPath.c_str(), dlMode);
                } else {
#if !defined(__ANDROID_RECOVERY__) && defined(__ANDROID__)
                    handle = android_load_sphal_library(fullPath.c_str(), dlMode);
#endif
                }

                if (handle == nullptr) {
                    const char* error = dlerror();
                    LOG(ERROR) << "Failed to dlopen " << lib << ": "
                               << (error == nullptr ? "unknown error" : error);
                    continue;
                }

                if (!eachLib(handle, lib, sym)) {
                    return;
                }
            }
        }
    }

    Return<sp<IBase>> get(const hidl_string& fqName,
                          const hidl_string& name) override {
        sp<IBase> ret = nullptr;

        openLibs(fqName, [&](void* handle, const std::string &lib, const std::string &sym) {
            IBase* (*generator)(const char* name);
            *(void **)(&generator) = dlsym(handle, sym.c_str());
            if(!generator) {
                const char* error = dlerror();
                LOG(ERROR) << "Passthrough lookup opened " << lib << " but could not find symbol "
                           << sym << ": " << (error == nullptr ? "unknown error" : error)
                           << ". Keeping library open.";

                // dlclose too problematic in multi-threaded environment
                // dlclose(handle);

                return true;  // continue
            }

            ret = (*generator)(name.c_str());

            if (ret == nullptr) {
                LOG(ERROR) << "Could not find instance '" << name.c_str() << "' in library " << lib
                           << ". Keeping library open.";

                // dlclose too problematic in multi-threaded environment
                // dlclose(handle);

                // this module doesn't provide this particular instance
                return true;  // continue
            }

            // Actual fqname might be a subclass.
            // This assumption is tested in vts_treble_vintf_test
            using ::android::hardware::details::getDescriptor;
            std::string actualFqName = getDescriptor(ret.get());
            CHECK(actualFqName.size() > 0);
            registerReference(actualFqName, name);
            return false;
        });

        return ret;
    }

    Return<bool> add(const hidl_string& /* name */,
                     const sp<IBase>& /* service */) override {
        LOG(FATAL) << "Cannot register services with passthrough service manager.";
        return false;
    }

    Return<Transport> getTransport(const hidl_string& /* fqName */,
                                   const hidl_string& /* name */) {
        LOG(FATAL) << "Cannot getTransport with passthrough service manager.";
        return Transport::EMPTY;
    }

    Return<void> list(list_cb /* _hidl_cb */) override {
        LOG(FATAL) << "Cannot list services with passthrough service manager.";
        return Void();
    }
    Return<void> listByInterface(const hidl_string& /* fqInstanceName */,
                                 listByInterface_cb /* _hidl_cb */) override {
        // TODO: add this functionality
        LOG(FATAL) << "Cannot list services with passthrough service manager.";
        return Void();
    }

    Return<bool> registerForNotifications(const hidl_string& /* fqName */,
                                          const hidl_string& /* name */,
                                          const sp<IServiceNotification>& /* callback */) override {
        // This makes no sense.
        LOG(FATAL) << "Cannot register for notifications with passthrough service manager.";
        return false;
    }

    Return<void> debugDump(debugDump_cb _hidl_cb) override {
        using Arch = ::android::hidl::base::V1_0::DebugInfo::Architecture;
        using std::literals::string_literals::operator""s;
        static std::string halLibPathVndkSp64 = details::getVndkSpHwPath("lib64");
        static std::string halLibPathVndkSp32 = details::getVndkSpHwPath("lib");
        static std::vector<std::pair<Arch, std::vector<const char*>>> sAllPaths{
            {Arch::IS_64BIT,
             {
                 HAL_LIBRARY_PATH_ODM_64BIT, HAL_LIBRARY_PATH_VENDOR_64BIT,
                 halLibPathVndkSp64.c_str(),
#ifndef __ANDROID_VNDK__
                 HAL_LIBRARY_PATH_SYSTEM_64BIT,
#endif
             }},
            {Arch::IS_32BIT,
             {
                 HAL_LIBRARY_PATH_ODM_32BIT, HAL_LIBRARY_PATH_VENDOR_32BIT,
                 halLibPathVndkSp32.c_str(),
#ifndef __ANDROID_VNDK__
                 HAL_LIBRARY_PATH_SYSTEM_32BIT,
#endif
             }}};
        std::map<std::string, InstanceDebugInfo> map;
        for (const auto &pair : sAllPaths) {
            Arch arch = pair.first;
            for (const auto &path : pair.second) {
                std::vector<std::string> libs = findFiles(path, "", ".so");
                for (const std::string &lib : libs) {
                    std::string matchedName;
                    std::string implName;
                    if (matchPackageName(lib, &matchedName, &implName)) {
                        std::string instanceName{"* ("s + path + ")"s};
                        if (!implName.empty()) instanceName += " ("s + implName + ")"s;
                        map.emplace(path + lib, InstanceDebugInfo{.interfaceName = matchedName,
                                                                  .instanceName = instanceName,
                                                                  .clientPids = {},
                                                                  .arch = arch});
                    }
                }
            }
        }
        fetchPidsForPassthroughLibraries(&map);
        hidl_vec<InstanceDebugInfo> vec;
        vec.resize(map.size());
        size_t idx = 0;
        for (auto&& pair : map) {
            vec[idx++] = std::move(pair.second);
        }
        _hidl_cb(vec);
        return Void();
    }

    Return<void> registerPassthroughClient(const hidl_string &, const hidl_string &) override {
        // This makes no sense.
        LOG(FATAL) << "Cannot call registerPassthroughClient on passthrough service manager. "
                   << "Call it on defaultServiceManager() instead.";
        return Void();
    }

    Return<bool> unregisterForNotifications(const hidl_string& /* fqName */,
                                            const hidl_string& /* name */,
                                            const sp<IServiceNotification>& /* callback */) override {
        // This makes no sense.
        LOG(FATAL) << "Cannot unregister for notifications with passthrough service manager.";
        return false;
    }

};

sp<IServiceManager1_0> getPassthroughServiceManager() {
    return getPassthroughServiceManager1_1();
}
sp<IServiceManager1_1> getPassthroughServiceManager1_1() {
    static sp<PassthroughServiceManager> manager(new PassthroughServiceManager());
    return manager;
}

PassthroughServiceManager 加载并创建,以获得原始服务对象的过程如下:

  1. 根据接口名称拼接动态链接库的文件名,如对于 IDevicesFactoryandroid.hardware.audio@6.0-impl,对于 IEffectsFactoryandroid.hardware.audio.effect@6.0-impl
  2. 尝试从几个路径查找对应的动态链接库文件,包括 /odm/lib/hw//vendor/lib/hw/ 等;
  3. 通过 dlopen() 动态加载找到的动态连接库文件;
  4. 在动态链接库里查找接口的 FETCH 函数,如对于 IDevicesFactoryHIDL_FETCH_IDevicesFactory,对于 IEffectsFactoryHIDL_FETCH_IEffectsFactory
  5. 调用找到的 FETCH 函数获取或创建对象;
  6. hwservicemanager 注册引用。

registerPassthroughServiceImplementation() 获取或创建了原始服务对象之后,会向 hwservicemanager 注册原始服务对象:

static void onRegistrationImpl(const std::string& descriptor, const std::string& instanceName) {
    LOG(INFO) << "Registered " << descriptor << "/" << instanceName;
    tryShortenProcessName(descriptor);
}
 . . . . . .
status_t registerAsServiceInternal(const sp<IBase>& service, const std::string& name) {
    if (service == nullptr) {
        return UNEXPECTED_NULL;
    }

    sp<IServiceManager1_2> sm = defaultServiceManager1_2();
    if (sm == nullptr) {
        return INVALID_OPERATION;
    }

    const std::string descriptor = getDescriptor(service.get());

    if (kEnforceVintfManifest && !isTrebleTestingOverride()) {
        using Transport = IServiceManager1_0::Transport;
        Return<Transport> transport = sm->getTransport(descriptor, name);

        if (!transport.isOk()) {
            LOG(ERROR) << "Could not get transport for " << descriptor << "/" << name << ": "
                       << transport.description();
            return UNKNOWN_ERROR;
        }

        if (transport != Transport::HWBINDER) {
            LOG(ERROR) << "Service " << descriptor << "/" << name
                       << " must be in VINTF manifest in order to register/get.";
            return UNKNOWN_ERROR;
        }
    }

    bool registered = false;
    Return<void> ret = service->interfaceChain([&](const auto& chain) {
        registered = sm->addWithChain(name.c_str(), service, chain).withDefault(false);
    });

    if (!ret.isOk()) {
        LOG(ERROR) << "Could not retrieve interface chain: " << ret.description();
    }

    if (registered) {
        onRegistrationImpl(descriptor, name);
    }

    return registered ? OK : UNKNOWN_ERROR;
}

registerAsServiceInternal() 通过 hwservicemanagerServiceManageraddWithChain() 接口注册服务,随后还会尝试缩短进程的进程名。这里注册 HIDL 服务的细节不去深究。

FETCH 函数

实现了 HAL 接口服务的动态链接库定义对应的 FETCH 函数。对于 IDevicesFactory 接口服务,核心 Android 系统有一个默认实现,位于 hardware/interfaces/audio/core/all-versions/default/DevicesFactory.cpp

IDevicesFactory* HIDL_FETCH_IDevicesFactory(const char* name) {
    return strcmp(name, "default") == 0 ? new DevicesFactory() : nullptr;
}

这个函数创建默认的原始服务对象 DevicesFactory

对于 IEffectsFactory 接口服务, 核心 Android 系统同样有一个默认实现,位于 hardware/interfaces/audio/effect/all-versions/default/EffectsFactory.cpp

IEffectsFactory* HIDL_FETCH_IEffectsFactory(const char* name) {
    return strcmp(name, "default") == 0 ? new EffectsFactory() : nullptr;
}

这个函数创建默认的原始服务对象 EffectsFactory

这些 FETCH 函数创建 default 实例的接口服务对象。

DevicesFactory 加载音频硬件模块

当 DevicesFactory 接口服务的客户,也就是 Audio flinger 请求打开设备时,DevicesFactory 加载音频硬件模块 (位于 hardware/interfaces/audio/core/all-versions/default/DevicesFactory.cpp):

#if MAJOR_VERSION == 2
Return<void> DevicesFactory::openDevice(IDevicesFactory::Device device, openDevice_cb _hidl_cb) {
    switch (device) {
        case IDevicesFactory::Device::PRIMARY:
            return openDevice<PrimaryDevice>(AUDIO_HARDWARE_MODULE_ID_PRIMARY, _hidl_cb);
        case IDevicesFactory::Device::A2DP:
            return openDevice(AUDIO_HARDWARE_MODULE_ID_A2DP, _hidl_cb);
        case IDevicesFactory::Device::USB:
            return openDevice(AUDIO_HARDWARE_MODULE_ID_USB, _hidl_cb);
        case IDevicesFactory::Device::R_SUBMIX:
            return openDevice(AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX, _hidl_cb);
        case IDevicesFactory::Device::STUB:
            return openDevice(AUDIO_HARDWARE_MODULE_ID_STUB, _hidl_cb);
    }
    _hidl_cb(Result::INVALID_ARGUMENTS, nullptr);
    return Void();
}
#elif MAJOR_VERSION >= 4
Return<void> DevicesFactory::openDevice(const hidl_string& moduleName, openDevice_cb _hidl_cb) {
    if (moduleName == AUDIO_HARDWARE_MODULE_ID_PRIMARY) {
        return openDevice<PrimaryDevice>(moduleName.c_str(), _hidl_cb);
    }
    return openDevice(moduleName.c_str(), _hidl_cb);
}
Return<void> DevicesFactory::openPrimaryDevice(openPrimaryDevice_cb _hidl_cb) {
    return openDevice<PrimaryDevice>(AUDIO_HARDWARE_MODULE_ID_PRIMARY, _hidl_cb);
}
#endif

Return<void> DevicesFactory::openDevice(const char* moduleName, openDevice_cb _hidl_cb) {
    return openDevice<implementation::Device>(moduleName, _hidl_cb);
}

template <class DeviceShim, class Callback>
Return<void> DevicesFactory::openDevice(const char* moduleName, Callback _hidl_cb) {
    audio_hw_device_t* halDevice;
    Result retval(Result::INVALID_ARGUMENTS);
    sp<DeviceShim> result;
    int halStatus = loadAudioInterface(moduleName, &halDevice);
    if (halStatus == OK) {
        result = new DeviceShim(halDevice);
        retval = Result::OK;
    } else if (halStatus == -EINVAL) {
        retval = Result::NOT_INITIALIZED;
    }
    _hidl_cb(retval, result);
    return Void();
}

// static
int DevicesFactory::loadAudioInterface(const char* if_name, audio_hw_device_t** dev) {
    const hw_module_t* mod;
    int rc;

    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;
    }
    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;
    }
    return OK;

out:
    *dev = NULL;
    return rc;
}

DevicesFactory 加载音频硬件模块的过程大体如下:

  1. 调用 hw_get_module_by_class(),根据硬件模块 ID 和模块名称加载硬件模块,创建 hw_module_t,对于音频来说,硬件模块 ID 为 audio,模块名称则来自于策略配置文件;
  2. 打开设备得到 audio_hw_device_t 结构。执行 hw_module_topen() 函数,这里实际获得的可能是音频硬件模块自定义的继承自 audio_hw_device_t 的结构,如对于 AAOS 版模拟器来说,是定义于 device/generic/car/emulator/audio/driver/audio_hw.hstruct generic_audio_device 结构对象;
  3. 检查音频硬件模块的版本,如果小于设备 API 最小版本,则关闭设备;
  4. 根据得到的 audio_hw_device_t 创建 implementation::Device 对象;
  5. 通过回调,返回创建的 implementation::Device 对象。

libhardware 中根据硬件模块 ID 和模块名称加载硬件模块的过程 (位于 hardware/libhardware/hardware.c) 如下:

#if !defined(__ANDROID_RECOVERY__)
#include <vndksupport/linker.h>
#endif

/** Base path of the hal modules */
#if defined(__LP64__)
#define HAL_LIBRARY_PATH1 "/system/lib64/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib64/hw"
#else
#define HAL_LIBRARY_PATH1 "/system/lib/hw"
#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
#define HAL_LIBRARY_PATH3 "/odm/lib/hw"
#endif

/**
 * There are a set of variant filename for modules. The form of the filename
 * is "<MODULE_ID>.variant.so" so for the led module the Dream variants 
 * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
 *
 * led.trout.so
 * led.msm7k.so
 * led.ARMV6.so
 * led.default.so
 */

static const char *variant_keys[] = {
    "ro.hardware",  /* This goes first so that it can pick up a different
                       file on the emulator. */
    "ro.product.board",
    "ro.board.platform",
    "ro.arch"
};

static const int HAL_VARIANT_KEYS_COUNT =
    (sizeof(variant_keys)/sizeof(variant_keys[0]));

/**
 * Load the file defined by the variant and if successful
 * return the dlopen handle and the hmi.
 * @return 0 = success, !0 = failure.
 */
static int load(const char *id,
        const char *path,
        const struct hw_module_t **pHmi)
{
    int status = -EINVAL;
    void *handle = NULL;
    struct hw_module_t *hmi = NULL;
#ifdef __ANDROID_VNDK__
    const bool try_system = false;
#else
    const bool try_system = true;
#endif

    /*
     * load the symbols resolving undefined symbols before
     * dlopen returns. Since RTLD_GLOBAL is not or'd in with
     * RTLD_NOW the external symbols will not be global
     */
    if (try_system &&
        strncmp(path, HAL_LIBRARY_PATH1, strlen(HAL_LIBRARY_PATH1)) == 0) {
        /* If the library is in system partition, no need to check
         * sphal namespace. Open it with dlopen.
         */
        handle = dlopen(path, RTLD_NOW);
    } else {
#if defined(__ANDROID_RECOVERY__)
        handle = dlopen(path, RTLD_NOW);
#else
        handle = android_load_sphal_library(path, RTLD_NOW);
#endif
    }
    if (handle == NULL) {
        char const *err_str = dlerror();
        ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
        status = -EINVAL;
        goto done;
    }

    /* Get the address of the struct hal_module_info. */
    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
    hmi = (struct hw_module_t *)dlsym(handle, sym);
    if (hmi == NULL) {
        ALOGE("load: couldn't find symbol %s", sym);
        status = -EINVAL;
        goto done;
    }

    /* Check that the id matches */
    if (strcmp(id, hmi->id) != 0) {
        ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
        status = -EINVAL;
        goto done;
    }

    hmi->dso = handle;

    /* success */
    status = 0;

    done:
    if (status != 0) {
        hmi = NULL;
        if (handle != NULL) {
            dlclose(handle);
            handle = NULL;
        }
    } else {
        ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
                id, path, hmi, handle);
    }

    *pHmi = hmi;

    return status;
}

/*
 * If path is in in_path.
 */
static bool path_in_path(const char *path, const char *in_path) {
    char real_path[PATH_MAX];
    if (realpath(path, real_path) == NULL) return false;

    char real_in_path[PATH_MAX];
    if (realpath(in_path, real_in_path) == NULL) return false;

    const size_t real_in_path_len = strlen(real_in_path);
    if (strncmp(real_path, real_in_path, real_in_path_len) != 0) {
        return false;
    }

    return strlen(real_path) > real_in_path_len &&
        real_path[real_in_path_len] == '/';
}

/*
 * Check if a HAL with given name and subname exists, if so return 0, otherwise
 * otherwise return negative.  On success path will contain the path to the HAL.
 */
static int hw_module_exists(char *path, size_t path_len, const char *name,
                            const char *subname)
{
    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH3, name, subname);
    if (path_in_path(path, HAL_LIBRARY_PATH3) && access(path, R_OK) == 0)
        return 0;

    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH2, name, subname);
    if (path_in_path(path, HAL_LIBRARY_PATH2) && access(path, R_OK) == 0)
        return 0;

#ifndef __ANDROID_VNDK__
    snprintf(path, path_len, "%s/%s.%s.so",
             HAL_LIBRARY_PATH1, name, subname);
    if (path_in_path(path, HAL_LIBRARY_PATH1) && access(path, R_OK) == 0)
        return 0;
#endif

    return -ENOENT;
}

int hw_get_module_by_class(const char *class_id, const char *inst,
                           const struct hw_module_t **module)
{
    int i = 0;
    char prop[PATH_MAX] = {0};
    char path[PATH_MAX] = {0};
    char name[PATH_MAX] = {0};
    char prop_name[PATH_MAX] = {0};


    if (inst)
        snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
    else
        strlcpy(name, class_id, PATH_MAX);

    /*
     * Here we rely on the fact that calling dlopen multiple times on
     * the same .so will simply increment a refcount (and not load
     * a new copy of the library).
     * We also assume that dlopen() is thread-safe.
     */

    /* First try a property specific to the class and possibly instance */
    snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
    if (property_get(prop_name, prop, NULL) > 0) {
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Loop through the configuration variants looking for a module */
    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
        if (property_get(variant_keys[i], prop, NULL) == 0) {
            continue;
        }
        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
            goto found;
        }
    }

    /* Nothing found, try the default */
    if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
        goto found;
    }

    return -ENOENT;

found:
    /* load the module, if this fails, we're doomed, and we should not try
     * to load a different variant. */
    return load(class_id, path, module);
}

int hw_get_module(const char *id, const struct hw_module_t **module)
{
    return hw_get_module_by_class(id, NULL, module);
}

这个过程主要包括这样一些步骤:

  1. 获得硬件模块名称。当实例名称不为空时,其构成为 硬件模块 ID.实例名称,如对于音频来说,实例名称可能为 primarya2dpusbr_submix,但 a2dp 不由 Audio HAL 服务处理,而是由 Audio a2dp HAL 处理,则这里获得的名称可能为 audio.primaryaudio.usbaudio.r_submix;当实例名称为空时,其构成为 硬件模块 ID,对于音频来说,即为 audio
  2. 根据硬件模块名称,构造对应的系统属性名称,用于获得子名称,对于音频来说,可能为 ro.hardware.audio.primaryro.hardware.audio.usbro.hardware.audio.r_submixro.hardware.audio
  3. 根据第 2 步中构造的系统属性名称,获得硬件模块子名称,对于 AAOS 版的模拟器而言,只定义了 ro.hardware.audio.primary,且其值为 caremu
  4. 根据硬件模块名称和硬件模块子名称构造动态链接库文件名,对于 AAOS 版模拟器而言,构造出来的文件名将为 audio.primary.caremu.so 等,然后依次检查这些文件在 /odm/lib64/hw/vendor/lib64/hw/system/lib64/hw 等目录下是否存在,若存在则加载动态链接库,否则继续查找;
  5. 依次尝试从 ro.hardwarero.product.boardro.board.platformro.arch 系统属性获得硬件模块子名称,若成功则同样根据硬件模块名称和硬件模块子名称构造动态链接库文件名,并检查文件在 /odm/lib64/hw/vendor/lib64/hw/system/lib64/hw 等目录下是否存在;若存在则加载动态链接库,否则继续查找;
  6. 检查以 default 为硬件模块子名称的模块动态链接库文件是否存在,若存在则加载动态链接库,否则返回错误;
  7. 加载硬件模块的实例的动态链接库文件。

从语义上来说,这里的过程如下:

  1. 构造硬件模块名称,其中包含硬件模块 ID 和实例名称;
  2. 获得硬件模块子名称,主要为尝试从多种系统属性中获取,系统属性中都找不到时使用 default 为子名称;
  3. 根据硬件模块名称和硬件模块子名称构造硬件模块的实例的动态链接库文件名;
  4. 依次检查硬件模块的实例的动态链接库文件在 /odm/lib64/hw/vendor/lib64/hw/system/lib64/hw 等目录下是否存在;
  5. 如果存在,就加载文件;如果都不存在,则返回错误。

对于 AAOS 版的模拟器来说,加载的音频硬件模块实例的动态链接库主要有 /vendor/lib/hw/audio.primary.caremu.so/system/lib64/hw/audio.a2dp.default.so/vendor/lib/hw/audio.r_submix.default.so

加载硬件模块的实例的动态链接库文件的过程如下:

  1. 通过 dlopen()android_load_sphal_library() 打开动态链接库文件;
  2. 找到其中定义的名为 HAL_MODULE_INFO_SYM_AS_STR,即 "HMI"struct hw_module_t 结构;
  3. 检查 ID 是否匹配;
  4. 通过传入的参数,返回找到的 struct hw_module_t 结构,对于音频硬件模块来说,这里实际获取的是 struct audio_module 对象。

尽管硬件模块主要使用 C 代码来定义接口并实现,但这些 C 代码同样采用了 OO 的思想,音频硬件模块实现相关的几个结构之间的关系如下:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rkxXGijf-1678363080484)(https://upload-images.jianshu.io/upload_images/1315506-a3bc27bddce9c9a4.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

Android Audio HAL 服务的整体结构如下:

audio hal,Android 音频,android

Audio HAL 接口服务的访问

IDevicesFactoryIEffectsFactory 接口服务主要在 AudioFlinger 中访问。AudioFlinger 访问这些接口服务时,首先创建它们的客户端代理对象,如下面的代码 (位于 frameworks/av/services/audioflinger/AudioFlinger.cpp) 所示:

    mDevicesFactoryHal = DevicesFactoryHalInterface::create();
    mEffectsFactoryHal = EffectsFactoryHalInterface::create();

这里的 DevicesFactoryHalInterface::create() 函数的定义 (位于 frameworks/av/media/libaudiohal/DevicesFactoryHalInterface.cpp) 如下:

namespace android {

// static
sp<DevicesFactoryHalInterface> DevicesFactoryHalInterface::create() {
    return createPreferredImpl<DevicesFactoryHalInterface>(
            "android.hardware.audio", "IDevicesFactory");
}

} // namespace android

这里调用的模板函数 createPreferredImpl() 的定义 (位于 frameworks/av/media/libaudiohal/include/media/audiohal/FactoryHalHidl.h) 如下:

namespace android {

namespace detail {

void* createPreferredImpl(const std::string& package, const std::string& interface);

}  // namespace detail

/** @Return the preferred available implementation or nullptr if none are available. */
template <class Interface>
static sp<Interface> createPreferredImpl(const std::string& package, const std::string& interface) {
    return sp<Interface>{static_cast<Interface*>(detail::createPreferredImpl(package, interface))};
}

} // namespace android

继续来看 detail::createPreferredImpl() 函数的定义 (位于 frameworks/av/media/libaudiohal/FactoryHalHidl.cpp):

namespace android::detail {

namespace {
/** Supported HAL versions, in order of preference.
 */
const char* sAudioHALVersions[] = {
    "7.0",
    "6.0",
    "5.0",
    "4.0",
    nullptr
};

bool createHalService(const std::string& version, const std::string& interface,
        void** rawInterface) {
    const std::string libName = "libaudiohal@" + version + ".so";
    const std::string factoryFunctionName = "create" + interface;
    constexpr int dlMode = RTLD_LAZY;
    void* handle = nullptr;
    dlerror(); // clear
    handle = dlopen(libName.c_str(), dlMode);
    if (handle == nullptr) {
        const char* error = dlerror();
        ALOGE("Failed to dlopen %s: %s", libName.c_str(),
                error != nullptr ? error : "unknown error");
        return false;
    }
    void* (*factoryFunction)();
    *(void **)(&factoryFunction) = dlsym(handle, factoryFunctionName.c_str());
    if (!factoryFunction) {
        const char* error = dlerror();
        ALOGE("Factory function %s not found in library %s: %s",
                factoryFunctionName.c_str(), libName.c_str(),
                error != nullptr ? error : "unknown error");
        dlclose(handle);
        return false;
    }
    *rawInterface = (*factoryFunction)();
    ALOGW_IF(!*rawInterface, "Factory function %s from %s returned nullptr",
            factoryFunctionName.c_str(), libName.c_str());
    return true;
}

bool hasHalService(const std::string& package, const std::string& version,
        const std::string& interface) {
    using ::android::hidl::manager::V1_0::IServiceManager;
    sp<IServiceManager> sm = ::android::hardware::defaultServiceManager();
    if (!sm) {
        ALOGE("Failed to obtain HIDL ServiceManager");
        return false;
    }
    // Since audio HAL doesn't support multiple clients, avoid instantiating
    // the interface right away. Instead, query the transport type for it.
    using ::android::hardware::Return;
    using Transport = IServiceManager::Transport;
    const std::string fqName = package + "@" + version + "::" + interface;
    const std::string instance = "default";
    Return<Transport> transport = sm->getTransport(fqName, instance);
    if (!transport.isOk()) {
        ALOGE("Failed to obtain transport type for %s/%s: %s",
                fqName.c_str(), instance.c_str(), transport.description().c_str());
        return false;
    }
    return transport != Transport::EMPTY;
}

}  // namespace

void* createPreferredImpl(const std::string& package, const std::string& interface) {
    for (auto version = detail::sAudioHALVersions; version != nullptr; ++version) {
        void* rawInterface = nullptr;
        if (hasHalService(package, *version, interface)
                && createHalService(*version, interface, &rawInterface)) {
            return rawInterface;
        }
    }
    return nullptr;
}

}  // namespace android::detail

createPreferredImpl() 函数的执行过程如下:

  1. 按照版本号,从高到低依次检查要创建的 HAL 服务是否存在,具体的方法是传入包名、版本、接口名称和实例名称等信息,向 hwservicemanager 请求获得相应的 transport 信息,如果可以获得有效的 transport 信息则说明相应的 HAL 服务存在,否则说明 HAL 不存在,这里向 hwservicemanager 请求获得相应的 transport 信息的方法,与我们前面看到的注册 HAL 接口服务对象时使用到的方法基本相同;
  2. 没有任何一个版本的要创建的 HAL 服务存在,则返回空值;
  3. 存在一个或多个版本的要创建的 HAL 服务,则创建版本最高的 HAL 服务;

创建 HAL 服务即创建相应的 HAL 接口服务的客户端代理,这个过程大体如下:

  1. 根据版本号获得相应版本的 libaudiohal@xx 动态链接库的文件名,如版本号是 7.0,则获得的动态链接库文件名为 libaudiohal@7.0.so
  2. 根据接口名称获得相应的创建函数的函数名,如对于 IDevicesFactory,获得的函数名为 createIDevicesFactory
  3. 使用 dlopen() 函数动态加载 libaudiohal@ 动态链接库;
  4. libaudiohal@ 动态链接库中查找创建函数的函数名;
  5. 调用创建函数创建接口对象。

libaudiohal@xxcreateIDevicesFactory 的定义 (位于 frameworks/av/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp) 如下:

extern "C" __attribute__((visibility("default"))) void* createIDevicesFactory() {
    auto service = hardware::audio::CPP_VERSION::IDevicesFactory::getService();
    return service ? new CPP_VERSION::DevicesFactoryHalHybrid(service) : nullptr;
}

IDevicesFactory 接口服务的客户端代理为 DevicesFactoryHalHybrid。顾名思义,这个类称为 HAL 混合接口,它混合了用于直接访问当前进程中的接口服务,和在 hwservicemanager 中注册的接口服务。在 DevicesFactoryHalHybrid 对象创建前,先获得了 hwservicemanager 中注册的接口服务的句柄。

DevicesFactoryHalHybrid 类的定义 (位于 frameworks/av/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp) 如下:

namespace CPP_VERSION {

DevicesFactoryHalHybrid::DevicesFactoryHalHybrid(sp<IDevicesFactory> hidlFactory)
        : mLocalFactory(new DevicesFactoryHalLocal()),
          mHidlFactory(new DevicesFactoryHalHidl(hidlFactory)) {
}

status_t DevicesFactoryHalHybrid::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    if (mHidlFactory != 0 && strcmp(AUDIO_HARDWARE_MODULE_ID_A2DP, name) != 0 &&
        strcmp(AUDIO_HARDWARE_MODULE_ID_HEARING_AID, name) != 0) {
        return mHidlFactory->openDevice(name, device);
    }
    return mLocalFactory->openDevice(name, device);
}

status_t DevicesFactoryHalHybrid::getHalPids(std::vector<pid_t> *pids) {
    if (mHidlFactory != 0) {
        return mHidlFactory->getHalPids(pids);
    }
    return INVALID_OPERATION;
}

status_t DevicesFactoryHalHybrid::setCallbackOnce(sp<DevicesFactoryHalCallback> callback) {
    if (mHidlFactory) {
        return mHidlFactory->setCallbackOnce(callback);
    }
    return INVALID_OPERATION;
}

} // namespace CPP_VERSION

getHalPids()setCallbackOnce() 主要是针对远程接口服务的。这里特别关注一下 openDevice() 函数。在要打开的音频硬件模块为 A2DP (“a2dp”) 或时 HEARING_AID (“hearing_aid”),通过 DevicesFactoryHalLocal 在当前进程中本地加载音频硬件模块并打开对应的设备;否则,通过 DevicesFactoryHalHidl 访问远程的接口服务。

来看下 DevicesFactoryHalLocal 类的定义 (位于 frameworks/av/media/libaudiohal/impl/DevicesFactoryHalLocal.cpp):

static status_t load_audio_interface(const char *if_name, audio_hw_device_t **dev)
{
    const hw_module_t *mod;
    int rc;

    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;
    }
    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 = BAD_VALUE;
        audio_hw_device_close(*dev);
        goto out;
    }
    return OK;

out:
    *dev = NULL;
    return rc;
}

status_t DevicesFactoryHalLocal::openDevice(const char *name, sp<DeviceHalInterface> *device) {
    audio_hw_device_t *dev;
    status_t rc = load_audio_interface(name, &dev);
    if (rc == OK) {
        *device = new DeviceHalLocal(dev);
    }
    return rc;
}

DevicesFactoryHalLocalopenDevice() 时,加载音频硬件模块,打开设备以创建或获得 audio_hw_device_t 对象,与我们前面看到的的远程访问的 IDevicesFactory 接口服务实现中的load_audio_interface() 完全一样,并基于 audio_hw_device_t 对象创建 DeviceHalLocal,即硬件设备的本地代理。

再来看下 DevicesFactoryHalHidl 类的 openDevice() 函数的定义 (位于 frameworks/av/media/libaudiohal/impl/DevicesFactoryHalHidl.cpp):

DevicesFactoryHalHidl::DevicesFactoryHalHidl(sp<IDevicesFactory> devicesFactory) {
    ALOG_ASSERT(devicesFactory != nullptr, "Provided default IDevicesFactory service is NULL");
    addDeviceFactory(devicesFactory, false /*needToNotify*/);
}

void DevicesFactoryHalHidl::onFirstRef() {
    sp<IServiceManager> sm = IServiceManager::getService();
    ALOG_ASSERT(sm != nullptr, "Hardware service manager is not running");
    sp<ServiceNotificationListener> listener = new ServiceNotificationListener(this);
    Return<bool> result = sm->registerForNotifications(
            IDevicesFactory::descriptor, "", listener);
    if (result.isOk()) {
        ALOGE_IF(!static_cast<bool>(result),
                "Hardware service manager refused to register listener");
    } else {
        ALOGE("Failed to register for hardware service manager notifications: %s",
                result.description().c_str());
    }
}

#if MAJOR_VERSION == 2
static IDevicesFactory::Device idFromHal(const char *name, status_t* status) {
    *status = OK;
    if (strcmp(name, AUDIO_HARDWARE_MODULE_ID_PRIMARY) == 0) {
        return IDevicesFactory::Device::PRIMARY;
    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_A2DP) == 0) {
        return IDevicesFactory::Device::A2DP;
    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_USB) == 0) {
        return IDevicesFactory::Device::USB;
    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_REMOTE_SUBMIX) == 0) {
        return IDevicesFactory::Device::R_SUBMIX;
    } else if(strcmp(name, AUDIO_HARDWARE_MODULE_ID_STUB) == 0) {
        return IDevicesFactory::Device::STUB;
    }
    ALOGE("Invalid device name %s", name);
    *status = BAD_VALUE;
    return {};
}
#elif MAJOR_VERSION >= 4
static const char* idFromHal(const char *name, status_t* status) {
    *status = OK;
    return name;
}
#endif

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 = factory->openDevice(
                hidlId,
                [&](Result r, const sp<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: ;
        }
    }
    ALOGW("The specified device name is not recognized: \"%s\"", name);
    return BAD_VALUE;
}

DevicesFactoryHalHidl 通过远程接口服务打开设备,获得远程设备的本地句柄,并基于该代理创建 DeviceHalHidl,即远程设备的本地代理。

Android Audio HAL 服务相关的各个角色的关系如下图:

audio hal,Android 音频,android

更具体一点来说,Android Audio HAL 服务的主要组成大体如下:

Audio HAL 服务独立进程

  1. android.hardware.audio.service
    代码位置:hardware/interfaces/audio/common/all-versions/default/service
    说明:Audio HAL 服务默认实现,其中强制包含 IDevicesFactoryIEffectsFactory 两个接口服务,可能包含 ISoundTriggerHwIBluetoothAudioProvidersFactoryIBluetoothAudioOffload 三个接口服务。

  2. android.hardware.audio.service-caremu
    代码位置:device/generic/car/emulator/audio/halservice
    设备中文件路径:/vendor/bin/hw/android.hardware.audio.service-caremu
    说明:AAOS 版模拟器中实际采用的 Audio HAL 服务,其中包含 IAudioControlIDevicesFactoryIEffectsFactory 三个接口服务。

IDevicesFactory 接口服务

  1. android.hardware.audio@x.x-impl
    代码位置:hardware/interfaces/audio/core/all-versions/default
    设备中文件路径:/vendor/lib/hw/android.hardware.audio@x.x-impl.so
    说明:默认实现,可为设备定制实现,如模拟器 goldfish 的实现 device/generic/goldfish/audio

音频硬件模块实例

  1. audio.primary.default
    代码位置:hardware/libhardware/modules/audio
    设备中文件路径:/vendor/lib64/hw/audio.primary.default.so
    说明:AudioFlinger 通过 IDevicesFactory 接口服务 远程访问,音频硬件模块 primary 实例的默认实现。

  2. audio.primary.caremu
    代码位置:device/generic/car/emulator/audio/driver
    设备中文件路径:/vendor/lib64/hw/audio.primary.caremu.so
    说明:AAOS 模拟器的定制实现,基于 tinyalsa 实现。AudioFlinger 通过 IDevicesFactory 接口服务 远程访问,音频硬件模块 primary 实例的实现。

  3. audio.a2dp.default
    代码位置:system/bt/audio_a2dp_hw
    设备中文件路径:/system/lib64/hw/audio.a2dp.default.so
    说明:AudioFlinger 通过 IDevicesFactory 接口服务 本地访问,音频硬件模块 a2dp 实例的默认实现。基于 OSI local socket 及 A2DP 控制命令实现。

  4. audio.r_submix.default
    代码位置:hardware/libhardware/modules/audio_remote_submix
    设备中文件路径:/vendor/lib/hw/audio.r_submix.default.so
    说明:AudioFlinger 通过 IDevicesFactory 接口服务 远程访问,音频硬件模块 r_submix 实例的默认实现。

IEffectsFactory 接口服务

  1. android.hardware.audio.effect@x.x-impl
    代码位置:hardware/interfaces/audio/effect/all-versions/default
    设备中文件路径:/vendor/lib/hw/android.hardware.audio.effect@x.x-impl.so
    说明:IEffectsFactory 接口服务 的默认实现,主要基于位于 frameworks/av/media/libeffects 的 libeffects 实现。

AudioControl 接口服务

代码位置:device/generic/car/emulator/audio/halservice
说明:AudioControl 服务 的 automotive 版模拟器实现,如同系统其它服务一样,通过 service manager 访问。

Done.文章来源地址https://www.toymoban.com/news/detail-612724.html

到了这里,关于Android Audio HAL 服务的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Audio HAL 提供的操作

    Audio HAL 本身主要包括接口服务层,和硬件模块层。接口服务层的接口一般在 HIDL 文件中定义,代码通过工具自动生成。接口服务层封装了硬件模块层,它们提供的操作最终还是要由硬件模块层完成。Audio HAL 硬件模块层相关的结构及其关系大体如下图所示: struct hw_module_t 的定

    2024年02月10日
    浏览(32)
  • Android 9 Audio系统笔记:AudioFlinger音频流处理流程

    好久没写了,今天碰巧有个小伙伴问我关于音频流这一块的,久了还有点记不起来,我就顺便写一下,后面就不用又找一遍代码了,所谓好记性不如烂笔头。 所以,这里是关于如何从AudioTrack 写入数据到audioflinger,以及audioflinger如何写入到hal层的音频流处理流程,主要写一下

    2023年04月08日
    浏览(37)
  • Android音频框架之一 详解audioPolicy流程及HAL驱动加载与配置

    android 系统 framework 代码起点, frameworks/base/core/jni/AndroidRuntime.cpp 文件, 此文件是android系统主线程代码,代码内容涉及系统很多模块,此程序主要是注册模块的JNI接口方法。其中涉及到模块 native、sensorHal、media、audioflinger、displayflinger、camera、serialport、binder等, 从各模块名称

    2024年01月22日
    浏览(39)
  • Android Audio - AAudio框架

    参考文献: Android AAudio 的实现分析_hanpfei的博客-CSDN博客  Android AAudio详解 - 简书 Android R音频输出问题处理随笔_audiodevicebroker_嘴巴吃糖了的博客-CSDN博客 

    2024年02月12日
    浏览(28)
  • Android Audio播放流程详解

    本文涉及的所有代码都是AOSP源码 Class Name Description AudioTrack Audio子系统对外提供的API类,用于音频数据的播放 AudioPolicyService Audio子系统的策略控制中心,控制设备的选择或者切换,以及音量控制 AudioFlinger Audio子系统的工作引擎,管理输入输出的音频流,音频数据的混音,以及

    2023年04月08日
    浏览(42)
  • Android Audio开发——概览(一)

            Audio 是 Android 系统中比较重要的一个模块,在 Android 中负责音频方面的数据流传输和控制功能,也负责音频设备的管理。         Android 音频架构定义了音频功能的实现方式,并指出实现中所涉及的相关源代码。 应用框架         应用框架包含应用代码,该

    2024年02月10日
    浏览(41)
  • Android Audio开发——录音(十七)

            AudioRecord 是安卓多媒体框架中用于录制音频的工具。它支持录制原始音频数据,即 PCM 数据,PCM 数据不能被播放器直接播放,需要编码压缩成常见音频格式才能被播放器识别。而我们之前分析的原生 api 中的 AudioTrack 可以直接播放 PCM 数据。         AudioRecord

    2024年02月11日
    浏览(40)
  • Android Audio实战——音量调节(十二)

             对于音量调节上一篇文章已经做了简单介绍,无论是软件调节还是硬件调节,最终实现都是调用到 AudioService。这一篇文章主要分析一下音量调节的相关代码。 1、音量调节接口         App在设置音量时,通常使用 AudioManager 的以下两个接口: 1、setStreamVolume(

    2024年02月15日
    浏览(44)
  • Android Qcom Audio入门学习

    总结: Android Audio不简单呀,一个人摸索入门不容易的,研究了一段时间,感觉还不是很懂,但以下的知识对入门还是有帮助的。 提供pcm的设备信息,将数据从用户空间传输到音频后端,以及从音频后端捕获录制等 vendor/qcom/opensource/audio-hal/primary-hal/msm8974/platform.c platform_init中

    2023年04月11日
    浏览(36)
  • Android Audio音量设置原理流程分析

    本篇文章主要介绍Android音量设置从App应用层到framework层执行流程,以及相关的细节和原理分析,建议在阅读此文章前去看博主的混音理论篇的声音的音量属性和声音相关公式的推导章节,这对阅读时理解音量等级、音量分贝计算有着很大的益处;如果阅读时发现文章有错误,

    2024年02月15日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包