Servicio HAL de audio de Android

En el sistema Android, el servicio Audio HAL se utiliza para administrar el acceso al hardware de audio y AudioFlinger accede al hardware de audio a través del servicio Audio HAL. Aquí tomamos la versión Android Automotive (AAOS) del simulador como ejemplo para observar el diseño, implementación y acceso del servicio Audio HAL. El análisis del código se basa en android-12.1.0_r27.

La implementación del servicio Audio HAL de la versión AAOS del emulador se encuentra en dispositivo/generic/car/emulator/audio/halservice . En el dispositivo Android, existirá como un proceso llamado android.hardware.audio.service-caremu. El host de este proceso La definición de función (ubicada en dispositivo/generic/car/emulator/audio/halservice/service.cpp ) es la siguiente:

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
}

El servicio Audio HAL consta de tres subservicios, a saber, IDevicesFactory , IEFfectsFactory y AudioControl . Los dos primeros son servicios de hardware. Están administrados por hwservicemanager implementado en system/hwservicemanager . El otro AudioControl se implementa mediante frameworks/native/cmds/servicemanager. gestión del administrador de servicios .

El registro del servicio AudioControl es relativamente fácil de entender y no se diferencia de otros servicios del sistema, como el servicio de administrador de actividades, el servicio de audio, etc. A continuación se muestra el registro de los servicios IDevicesFactory e IEFfectsFactory . Todos están registrados a través de la función de plantilla registerPassthroughServiceImplementation(). La definición de esta función (ubicada en system/libhidl/transport/include/hidl/LegacySupport.h ) es la siguiente:

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);
}

Esta función registra defaultuna versión del servicio de interfaz denominada , que es la versión predeterminada.

La definición de función llamada aquí registerPassthroughServiceImplementation()(ubicada en system/libhidl/transport/LegacySupport.cpp ) es la siguiente:

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);
}

IDevicesFactoryy IEffectsFactoryse declaran en hidl, cuyo código es generado automáticamente por la herramienta, como por ejemplo IDevicesFactory, aquí registerPassthroughServiceImplementation()el nombre de la interfaz recibida interfaceNamees [email protected]::IDevicesFactory, para IEffectsFactory, el nombre de la interfaz es [email protected]::IEffectsFactoryy el nombre del servicio serviceNamees ambos default.

registerPassthroughServiceImplementation()El proceso principal de ejecución de la función aquí se puede dividir en tres pasos:

  1. Obtenga el objeto de servicio original según el nombre de la interfaz y el nombre del servicio, que se getRawServiceInternal(interfaceName, serviceName, true /*retry*/, true /*getStub*/)realiza principalmente a través de;
  2. Realice algunas comprobaciones en el objeto de servicio obtenido, incluido si es remoto, el valor del descriptor, etc. El marco HIDL de Android permite que el nombre del servicio entrante sea inconsistente con el nombre del servicio esperado, lo que probablemente permita el acceso real al servicio secundario. a través de la interfaz del servicio principal . ;
  3. Registre el servicio con hwservicemanager , que se registerAsServiceInternal(service, name)realiza principalmente a través de.

getRawServiceInternal()La definición de la función (ubicada en system/libhidl/transport/ServiceManagement.cpp ) es la siguiente:

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

El principal proceso de ejecución de esta función es el siguiente:

  1. Obtenga el tipo de transporte de la instancia correspondiente del servicio de interfaz, cuando kIsRecoveryes true, es directamente Transport::PASSTHROUGH, de lo contrario se obtiene de hwservicemanager . El significado del tipo de transporte del servicio de interfaz HIDL se verá más adelante.
  2. En algunos casos, principalmente cuando el tipo de transporte es Transport::HWBINDERy no se obtiene stub () getStub, intente obtener el objeto de servicio original de hwservicemanager . Si tiene éxito, el objeto de servicio original obtenido se devolverá directamente; de ​​lo contrario, continúe la ejecución; aquí, obtenga de hwservicemanager El objeto de servicio original lo intentará varias veces. Se utiliza para controlar si se debe obtener por la fuerza el objeto de servicio de interfaz no empaquetado. Para las funciones getStubque desean registrar servicios , es porque necesita crear un objeto de la instancia de servicio de interfaz en el proceso actual y luego registrarlo en hwservicemanager .registerPassthroughServiceImplementation()getStubtrue
  3. Obtenga el objeto de servicio original del administrador de servicios de transferencia y devuelva el objeto de servicio original obtenido si tiene éxito; de lo contrario, devuelva un valor nulo. La definición de administrador de servicios Passthrough explica Transport::PASSTHROUGHel significado hasta cierto punto.

En hwservicemanager , cuando recibe una solicitud de tipo de transporte para obtener una instancia de un servicio de interfaz, obtendrá esta información del archivo de manifiesto. La definición ServiceManager::getTransport()de la función (ubicada en system/hwservicemanager/ServiceManager.cpp ) es la siguiente:

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

Aquí utilizamos principalmente ::android::hardware::getTransport()la función para obtener el tipo de transporte de la instancia del servicio de interfaz. La definición de esta función (ubicada en system/hwservicemanager/Vintf.cpp ) es la siguiente:

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()Obtenga el tipo de transporte del servicio de interfaz del archivo de manifiesto. Primero intenta obtenerlo del archivo de manifiesto de Framework Hal y, si eso falla, intenta obtenerlo del archivo de manifiesto de Device Hal. Archivo de manifiesto de Framework Hal, que incluye lo siguiente en orden de prioridad:

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

Archivo de manifiesto del dispositivo Hal, que incluye lo siguiente en orden de prioridad:

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.

Se puede ver en vintf::VintfObjectla definición de la función (ubicada en 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;
}

Para la versión AAOS del emulador, IDevicesFactoryel archivo de manifiesto es device/generic/car/emulator/audio/driver/[email protected] y su contenido principal es:

<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>

Es decir, el tipo Tansport de este servicio de interfaz es Transport::HWBINDER. En el dispositivo, la ruta a este archivo es /vendor/etc/vintf/manifest/[email protected] .

IEffectsFactoryEl archivo de manifiesto es device/generic/car/emulator/audio/[email protected] y su contenido principal es:

<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>

El tipo de Tansport servido por esta interfaz también es Transport::HWBINDER. En el dispositivo, el contenido de este archivo se fusionará y se colocará en /vendor/etc/vintf/manifest.xml .

Para el servicio Audio HAL, dado que necesita crear el objeto de la instancia del servicio de interfaz por sí mismo, omitirá la acción de obtener el objeto de la instancia del servicio de interfaz de hwservicemanager y será cargado y creado por el administrador de servicios de transferencia en el proceso actual para obtener el objeto de servicio original.

PassthroughServiceManagerLa definición (ubicada en system/libhidl/transport/ServiceManagement.cpp ) es la siguiente:

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 [email protected]::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;
}

PassthroughServiceManagerEl proceso de carga y creación para obtener el objeto de servicio original es el siguiente:

  1. El nombre del archivo de la biblioteca de enlaces dinámicos se empalma según el nombre de la interfaz, IDevicesFactorycomo [email protected] para [email protected] ;IEffectsFactory
  2. Intente encontrar los archivos de biblioteca de vínculos dinámicos correspondientes en varias rutas, incluidas /odm/lib/hw/ y /vendor/lib/hw/ , etc.;
  3. dlopen()Archivos de biblioteca de enlaces dinámicos encontrados mediante carga dinámica;
  4. Busque la función FETCH de la interfaz en la biblioteca de enlaces dinámicos, como for IDevicesFactoryy HIDL_FETCH_IDevicesFactoryfor ;IEffectsFactoryHIDL_FETCH_IEffectsFactory
  5. Llame a la función FETCH encontrada para obtener o crear un objeto;
  6. Registre una referencia con hwservicemanager .

registerPassthroughServiceImplementation()Una vez obtenido o creado el objeto de servicio original, hwservicemanagerel objeto de servicio original se registrará en:

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()Registre el servicio a través de la interfaz de hwservicemanager y luego intente acortar el nombre del proceso. No entraré en detalles sobre cómo registrar el servicio HIDL aquí.ServiceManageraddWithChain()

función BUSCAR

La biblioteca de enlaces dinámicos que implementa el servicio de interfaz HAL define la función FETCH correspondiente. Para IDevicesFactorylos servicios de interfaz, el sistema Android central tiene una implementación predeterminada ubicada en hardware/interfaces/audio/core/all-versions/default/DevicesFactory.cpp :

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

Esta función crea el objeto de servicio sin formato predeterminado DevicesFactory.

Para IEffectsFactorylos servicios de interfaz, el sistema Android central también tiene una implementación predeterminada, ubicada en hardware/interfaces/audio/effect/all-versions/default/EffectsFactory.cpp :

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

Esta función crea el objeto de servicio sin formato predeterminado EffectsFactory.

Estas funciones FETCH crean defaultinstancias de objetos de servicio de interfaz.

DevicesFactory carga el módulo de hardware de audio

Cuando el cliente atendido por la interfaz DevicesFactory, es decir, Audio Flinger, solicita abrir el dispositivo, DevicesFactory carga el módulo de hardware de audio (ubicado en 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;
}

El proceso de carga del módulo de hardware de audio en DevicesFactory es aproximadamente el siguiente:

  1. Llame hw_get_module_by_class(), cargue el módulo de hardware según el ID del módulo de hardware y el nombre del módulo, cree hw_module_t, para audio, el ID del módulo de hardware es audioy el nombre del módulo proviene del archivo de configuración de políticas;
  2. Abra el dispositivo para obtener audio_hw_device_tla estructura. Ejecute la función hw_module_tde open(), lo que realmente se obtiene aquí puede ser la estructura personalizada del módulo de hardware de audio heredado de audio_hw_device_t, por ejemplo, para la versión AAOS del simulador, es la estructura definida en dispositivo/generic/car/emulator/audio/struct generic_audio_device objeto controlador/audio_hw.h ;
  3. Verifique la versión del módulo de hardware de audio y, si es inferior a la versión mínima de API del dispositivo, apague el dispositivo;
  4. audio_hw_device_tCrea un objeto basado en lo obtenido implementation::Device;
  5. Mediante devolución de llamada, devuelve el implementation::Deviceobjeto creado.

El proceso de carga de módulos de hardware según el ID del módulo de hardware y el nombre del módulo en libhardware (ubicado en hardware/libhardware/hardware.c ) es el siguiente:

#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);
}

Este proceso incluye principalmente los siguientes pasos:

  1. Obtenga el nombre del módulo de hardware. Cuando el nombre de la instancia no está vacío, está compuesto por 硬件模块 ID.实例名称, por ejemplo, para audio, el nombre de la instancia puede ser primary, a2dpy , pero no lo procesa el servicio Audio HAL, sino el Audio a2dp HAL, luego se obtiene el nombre usb. aquí puede ser y ; cuando el nombre de la instancia está vacío, se compone de , para audio, es decir .r_submixa2dpaudio.primaryaudio.usbaudio.r_submix硬件模块 IDaudio
  2. Según el nombre del módulo de hardware, construya el nombre del atributo del sistema correspondiente para obtener el subnombre. Para audio, puede ser ro.hardware.audio.primary, y ;ro.hardware.audio.usbro.hardware.audio.r_submixro.hardware.audio
  3. De acuerdo con el nombre del atributo del sistema construido en el paso 2, obtenga el subnombre del módulo de hardware. Para la versión AAOS del simulador, solo está definido ro.hardware.audio.primaryy su valor es caremu;
  4. Construya el nombre del archivo de la biblioteca de enlaces dinámicos según el nombre del módulo de hardware y el subnombre del módulo de hardware. Para la versión AAOS del simulador, el nombre del archivo construido será etc., y luego verifique estos archivos audio.primary.caremu.soen /odm/lib64/hw , /vendor /lib64/ Si existen en directorios como hw y /system/lib64/hw, si existen, cargue la biblioteca de enlaces dinámicos, de lo contrario continúe buscando;
  5. Intente obtener el subnombre del módulo de hardware de las propiedades del sistema de hwyro.hardware, y /system/lib64/hw ; si existen, cargue la biblioteca de vínculos dinámicos; de lo contrario, continúe buscando;ro.product.boardro.board.platformro.arch
  6. defaultCompruebe si existe el archivo de biblioteca de enlaces dinámicos del módulo con el subnombre del módulo de hardware. Si existe, cargue la biblioteca de enlaces dinámicos; de lo contrario, se devolverá un error;
  7. Cargue el archivo de biblioteca de vínculos dinámicos de la instancia del módulo de hardware.

Semánticamente, el proceso aquí es el siguiente:

  1. Construya el nombre del módulo de hardware, que contiene la ID del módulo de hardware y el nombre de la instancia;
  2. Obtenga el subnombre del módulo de hardware, principalmente tratando de obtenerlo de múltiples propiedades del sistema. Cuando no se pueda encontrar en las propiedades del sistema, utilícelo defaultcomo subnombre;
  3. Construya el nombre del archivo de la biblioteca de enlaces dinámicos de la instancia del módulo de hardware en función del nombre del módulo de hardware y el subnombre del módulo de hardware;
  4. Compruebe a su vez si los archivos de la biblioteca de vínculos dinámicos de las instancias del módulo de hardware existen en directorios como /odm/lib64/hw , /vendor/lib64/hw y /system/lib64/hw ;
  5. Si existe, carga el archivo; si no existe, se devuelve un error.

Para la versión AAOS del simulador, las bibliotecas de enlaces dinámicos de las instancias del módulo de hardware de audio cargadas incluyen principalmente /vendor/lib/hw/audio.primary.caremu.so y /system/lib64/hw/audio.a2dp.default.so y /vendor/lib/hw/audio.r_submix.default.so .

El proceso de carga del archivo de biblioteca de vínculos dinámicos de una instancia de un módulo de hardware es el siguiente:

  1. Abra el archivo de la biblioteca de vínculos dinámicos mediante dlopen()o ;android_load_sphal_library()
  2. Encuentre la estructura nombrada, es decir, definida en HAL_MODULE_INFO_SYM_AS_STRella ;"HMI"struct hw_module_t
  3. Compruebe si la identificación coincide;
  4. A través de los parámetros entrantes se devuelve la struct hw_module_testructura encontrada, para el módulo de hardware de audio lo que realmente se obtiene aquí es struct audio_moduleel objeto.

Aunque el módulo de hardware utiliza principalmente código C para definir e implementar la interfaz, estos códigos C también adoptan ideas OO. La relación entre varias estructuras relacionadas con la implementación del módulo de hardware de audio es la siguiente:

[La transferencia de la imagen del enlace externo falló. El sitio de origen puede tener un mecanismo anti-leeching. Se recomienda guardar la imagen y cargarla directamente (img-rkxXGijf-1678363080484)(https://upload-images.jianshu.io/ upload_images/1315506-a3bc27bddce9c9a4.png ?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)]

La estructura general del servicio Android Audio HAL es la siguiente:

Arquitectura de servicio de audio HAL

Acceso a los servicios de la interfaz Audio HAL

Se accede a los servicios de interfaz IDevicesFactory e IEFfectsFactory principalmente en AudioFlinger. Cuando AudioFlinger accede a estos servicios de interfaz, primero crea sus objetos proxy de cliente, como se muestra en el siguiente código (ubicado en frameworks/av/services/audioflinger/AudioFlinger.cpp ):

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

La definición de la función aquí DevicesFactoryHalInterface::create()(ubicada en frameworks/av/media/libaudiohal/DevicesFactoryHalInterface.cpp ) es la siguiente:

namespace android {

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

} // namespace android

La definición de la función de plantilla llamada aquí createPreferredImpl()(ubicada en frameworks/av/media/libaudiohal/include/media/audiohal/FactoryHalHidl.h ) es la siguiente:

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

Continúe mirando detail::createPreferredImpl()la definición de la función (ubicada en 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()El proceso de ejecución de la función es el siguiente:

  1. Verifique si el servicio HAL a crear existe de acuerdo con el número de versión de mayor a menor, el método específico es pasar el nombre del paquete, la versión, el nombre de la interfaz, el nombre de la instancia y otra información, y solicite a hwservicemanager que obtenga el transporte correspondiente. información. Si es válida La información de transporte indica que el servicio HAL correspondiente existe, de lo contrario significa que HAL no existe. El método para solicitar la información de transporte correspondiente de hwservicemanager aquí es básicamente el mismo que el método utilizado al registrar el servicio de interfaz HAL objeto que vimos antes;
  2. Si no existe ninguna versión del servicio HAL que se va a crear, se devuelve un valor nulo;
  3. Si hay una o más versiones del servicio HAL por crear, se crea el servicio HAL con la versión más alta;

Crear un servicio HAL significa crear un proxy de cliente para el servicio de interfaz HAL correspondiente. El proceso es aproximadamente el siguiente:

  1. Obtenga el nombre de archivo de la versión correspondiente de la biblioteca de enlaces dinámicos libaudiohal@xx7.0 de acuerdo con el número de versión. Si el número de versión es , el nombre del archivo de la biblioteca de enlaces dinámicos obtenido es [email protected] ;
  2. Obtenga el nombre de la función de creación correspondiente según el nombre de la interfaz.Por ejemplo, para IDevicesFactory , el nombre de la función obtenida es createIDevicesFactory ;
  3. Utilice dlopen()la función para cargar dinámicamente la biblioteca de enlaces dinámicos libaudiohal@ ;
  4. Busque el nombre de la función creada en la biblioteca de enlaces dinámicos libaudiohal@ ;
  5. Llame a la función de creación para crear el objeto de interfaz.

La definición en libaudiohal@xx (ubicada en frameworks /av/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp ) es la siguiente:createIDevicesFactory

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

Es decir, IDevicesFactoryel proxy del cliente para el servicio de interfaz es DevicesFactoryHalHybrid. Como sugiere el nombre, esta clase se llama interfaz híbrida HAL, que combina servicios de interfaz para acceso directo al proceso actual y servicios de interfaz registrados en hwservicemanager. Antes de DevicesFactoryHalHybridcrear el objeto, se obtiene el identificador del servicio de interfaz registrado en hwservicemanager.

DevicesFactoryHalHybridLa definición de la clase (ubicada en frameworks/av/media/libaudiohal/impl/DevicesFactoryHalHybrid.cpp ) es la siguiente:

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()y setCallbackOnce()son principalmente para servicios de interfaz remota. Preste especial atención a openDevice()las funciones aquí. Cuando el módulo de hardware de audio a abrir sea A2DP ("a2dp") o HEARING_AID ("hearing_aid"), DevicesFactoryHalLocalcargue el módulo de hardware de audio localmente en el proceso actual y abra el dispositivo correspondiente; en caso contrario, acceda al DevicesFactoryHalHidlservicio de interfaz remota.

Echemos un vistazo a la DevicesFactoryHalLocaldefinición de clase (ubicada en 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;
}

DevicesFactoryHalLocalEn openDevice(), se carga el módulo de hardware de audio y se abre el dispositivo para crear u obtener un objeto, exactamente igual que audio_hw_device_ten la implementación del servicio de interfaz IDevicesFactory de acceso remoto que vimos anteriormente, y basado en la creación del objeto , es decir, el proxy local. del dispositivo de hardware.load_audio_interface()audio_hw_device_tDeviceHalLocal

Echemos un vistazo a la definición de DevicesFactoryHalHidlla función de clase openDevice()(ubicada en 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;
}

DevicesFactoryHalHidlAbra el dispositivo a través del servicio de interfaz remota, obtenga el identificador local del dispositivo remoto y cree un proxy basado en el dispositivo remoto DeviceHalHidl, es decir, el proxy local del dispositivo remoto.

La relación entre los distintos roles relacionados con el servicio Android Audio HAL es la siguiente:

Audio HAL Servicio C/S Lado

Más específicamente, los componentes principales del servicio Android Audio HAL son aproximadamente los siguientes:

Proceso independiente del servicio Audio HAL

  1. Ubicación del código android.hardware.audio.service
    : hardware/interfaces/audio/common/all-versions/default/service Descripción: la implementación predeterminada
    del servicio Audio HAL, que es obligatorio para incluir dos servicios de interfaz y puede incluir y tres servicios de interfaz.IDevicesFactoryIEffectsFactoryISoundTriggerHwIBluetoothAudioProvidersFactoryIBluetoothAudioOffload

  2. android.hardware.audio.service-caremu
    Ubicación del código: dispositivo/generic/car/emulator/audio/halservice
    Ruta del archivo en el dispositivo: /vendor/bin/hw/android.hardware.audio.service-caremu
    Descripción: Simulador de versión AAOS El servicio Audio HAL realmente utilizado en , que incluye tres servicios de interfaz IAudioControl: IDevicesFactoryy .IEffectsFactory

Servicio de interfaz IDevicesFactory

  1. android.hardware.audio@xx-impl
    ubicación del código: hardware/interfaces/audio/core/all-versions/default
    Ruta del archivo en el dispositivo: /vendor/lib/hw/[email protected]
    Descripción : La implementación predeterminada se puede personalizar para el dispositivo, como la implementación del simulador goldfish device/generic/goldfish/audio .

Ejemplo de módulo de hardware de audio

  1. ubicación del código audio.primary.default
    : hardware/libhardware/modules/
    ruta del archivo de audio en el dispositivo: /vendor/lib64/hw/audio.primary.default.so
    Descripción: AudioFlinger ofrece acceso remoto a través de la interfaz IDevicesFactoryprimary , la opción predeterminada para audio las instancias del módulo de hardware logran.

  2. Ubicación del código audio.primary.caremu
    : dispositivo/generic/car/emulator/audio/driver
    Ruta del archivo en el dispositivo: /vendor/lib64/hw/audio.primary.caremu.so
    Descripción: Implementación personalizada del simulador AAOS, basada en tinyalsa implementación. AudioFlinger ofrece acceso remoto a través de la interfaz IDevicesFactory , primaryla implementación de instancias de módulos de hardware de audio.

  3. ubicación del código audio.a2dp.default
    : ruta del archivo en system/bt/audio_a2dp_hw dispositivo: /system/lib64/hw/audio.a2dp.default.so Descripción: AudioFlinger ofrece acceso local a través de la interfaz IDevicesFactory , la implementación predeterminada del hardware de audio. instancia del módulo. Implementado en base a socket local OSI y comandos de control A2DP.

    a2dp

  4. ubicación del código audio.r_submix.default
    : hardware/libhardware/modules/audio_remote_submix
    ruta del archivo en el dispositivo: /vendor/lib/hw/audio.r_submix.default.so
    Descripción: AudioFlinger ofrece acceso remoto a través de la interfaz IDevicesFactoryr_submix , la opción predeterminada para audio las instancias del módulo de hardware logran.

Servicio de interfaz IEFfectsFactory

  1. android.hardware.audio.effect@xx-impl
    Ubicación del código: hardware/interfaces/audio/effect/all-versions/default
    Ruta del archivo en el dispositivo: /vendor/lib/hw/android.hardware.audio.effect@xx- Descripción de impl .so
    : La implementación predeterminada del servicio de interfaz IEffectsFactory se basa principalmente en la implementación de libeffects ubicada en frameworks/av/media/libeffects .

Servicio de interfaz AudioControl

Ubicación del código: dispositivo/genérico/coche/emulador/audio/halservice
Descripción: Se accede a la versión automotriz de la implementación del simulador del servicio AudioControl , al igual que a otros servicios del sistema, a través del administrador de servicios.

Hecho.

Supongo que te gusta

Origin blog.csdn.net/tq08g2z/article/details/129430025
Recomendado
Clasificación