Android——hal库加载操作流程

来源:互联网 发布:qt多窗口编程 编辑:程序博客网 时间:2024/06/05 03:12

系统是如何区分平台,加载操作指定平台的相应的HAL库文件的?

以加载audio.primary.msm8909.so为例:
高通平台,audio primary库文件是有两个的,但是具体加载哪一个呢?

audio.primary.default.so
audio.primary.msm8909.so

AudioFlinger开始的调用流程:

audio_module_handle_t AudioFlinger::loadHwModule(const char *name)
|——audio_module_handle_t AudioFlinger::loadHwModule_l(const char *name)
|——static int load_audio_interface(const char *if_name, audio_hw_device_t **dev)

static int 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);//"audio" hal操作句柄,根据这个去加载hal,if_name为“primary”    ALOGE_IF(rc, "%s couldn't load audio hw module %s.%s (%s)", __func__,                 AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));    if (rc) {        goto out;    }    rc = audio_hw_device_open(mod, dev);//操作HAL的adev_open函数    ALOGE_IF(rc, "%s couldn't open audio hw device in %s.%s (%s)", __func__,                 AUDIO_HARDWARE_MODULE_ID, if_name, strerror(-rc));    if (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;        goto out;    }    return 0;out:    *dev = NULL;    return rc;}

hardware/libhardware/hardware.c

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);  //从上面传下来的name值就是  "audio.primary"    /*     * 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);//查找属性值是否“ro.hardware.audio.primary” 这个属性值其实并没有设置    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++) {    //鉴于上面的属性值并没有找到,就去查找数组variant_keys是否有相关设置   /*   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"};   */        if (property_get(variant_keys[i], prop, NULL) == 0) {            continue;  //如果当前遍历属性值没有设置,开启查找下一个属性值        }        if (hw_module_exists(path, sizeof(path), name, prop) == 0) {        //hw_module_exists实质是加上路径查找指定的库            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);}

那么以下属性值是在哪里赋值的呢

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” }; “ro.hardware.%s”

以当前所操作的机器来看:

[ro.hardware]: [qcom]
[ro.product.board]: [msm8909]
[ro.board.platform]: [msm8909]
“ro.arch” 没有被设置
ro.hardware.audio.primary 没有被设置

build/tools/buildinfo.sh中间:
echo “ro.board.platform=$TARGET_BOARD_PLATFORM”

device/jrdcom/projectname/BoardConfig.mk中间赋值:
TARGET_BOARD_PLATFORM := msm8909

到这里就很清楚了
AudioPolicyManager初始化的时候,通过如下代码,根据指定的配置文件加载相应的audio hal库文件:

   AudioPolicyConfig config(mHwModules, mAvailableOutputDevices, mAvailableInputDevices,                             mDefaultOutputDevice, speakerDrcEnabled,                             static_cast<VolumeCurvesCollection *>(mVolumeCurves));    PolicySerializer serializer;    if (serializer.deserialize(AUDIO_POLICY_XML_CONFIG_FILE, config) != NO_ERROR) {    //AUDIO_POLICY_XML_CONFIG_FILE "/system/etc/audio_policy_configuration.xml"    。。。    }

最后,附上加载函数:

/** * 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;    /*     * 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     */    handle = dlopen(path, RTLD_NOW);//操作文件    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, *pHmi, handle);    }    *pHmi = hmi;    return status;}
原创粉丝点击