hardware.c revision 2b811adcbc821573de53a15f3d4e85a3d5a4ef9b
1/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <hardware/hardware.h>
18
19#include <cutils/properties.h>
20
21#include <dlfcn.h>
22#include <string.h>
23#include <pthread.h>
24#include <errno.h>
25#include <limits.h>
26
27#define LOG_TAG "HAL"
28#include <utils/Log.h>
29
30/** Base path of the hal modules */
31#define HAL_LIBRARY_PATH "/system/lib/hw"
32
33/**
34 * There are a set of variant filename for modules. The form of the filename
35 * is "<MODULE_ID>.variant.so" so for the led module the Dream variants
36 * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
37 *
38 * led.trout.so
39 * led.msm7k.so
40 * led.ARMV6.so
41 * led.default.so
42 */
43
44static const char *variant_keys[] = {
45    "ro.hardware",  /* This goes first so that it can pick up a different
46                       file on the emulator. */
47    "ro.product.board",
48    "ro.board.platform",
49    "ro.arch"
50};
51
52static const int HAL_VARIANT_KEYS_COUNT =
53    (sizeof(variant_keys)/sizeof(variant_keys[0]));
54
55/**
56 * Load the file defined by the variant and if successful
57 * return the dlopen handle and the hmi.
58 * @return 0 = success, !0 = failure.
59 */
60static int load(const char *id,
61        const char *path,
62        const struct hw_module_t **pHmi)
63{
64    int status;
65    void *handle;
66    struct hw_module_t *hmi;
67
68    /*
69     * load the symbols resolving undefined symbols before
70     * dlopen returns. Since RTLD_GLOBAL is not or'd in with
71     * RTLD_NOW the external symbols will not be global
72     */
73    handle = dlopen(path, RTLD_NOW);
74    if (handle == NULL) {
75        char const *err_str = dlerror();
76        LOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
77        status = -EINVAL;
78        goto done;
79    }
80
81    /* Get the address of the struct hal_module_info. */
82    const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
83    hmi = (struct hw_module_t *)dlsym(handle, sym);
84    if (hmi == NULL) {
85        LOGE("load: couldn't find symbol %s", sym);
86        status = -EINVAL;
87        goto done;
88    }
89
90    /* Check that the id matches */
91    if (strcmp(id, hmi->id) != 0) {
92        LOGE("load: id=%s != hmi->id=%s", id, hmi->id);
93        status = -EINVAL;
94        goto done;
95    }
96
97    hmi->dso = handle;
98
99    /* success */
100    status = 0;
101
102    done:
103    if (status != 0) {
104        hmi = NULL;
105        if (handle != NULL) {
106            dlclose(handle);
107            handle = NULL;
108        }
109    } else {
110        LOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
111                id, path, *pHmi, handle);
112    }
113
114    *pHmi = hmi;
115
116    return status;
117}
118
119int hw_get_module(const char *id, const struct hw_module_t **module)
120{
121    int status;
122    int i;
123    const struct hw_module_t *hmi = NULL;
124    char prop[PATH_MAX];
125    char path[PATH_MAX];
126
127    /*
128     * Here we rely on the fact that calling dlopen multiple times on
129     * the same .so will simply increment a refcount (and not load
130     * a new copy of the library).
131     * We also assume that dlopen() is thread-safe.
132     */
133
134    /* Loop through the configuration variants looking for a module */
135    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) {
136        if (i < HAL_VARIANT_KEYS_COUNT) {
137            if (property_get(variant_keys[i], prop, NULL) == 0) {
138                continue;
139            }
140            snprintf(path, sizeof(path), "%s/%s.%s.so",
141                    HAL_LIBRARY_PATH, id, prop);
142        } else {
143            snprintf(path, sizeof(path), "%s/%s.default.so",
144                    HAL_LIBRARY_PATH, id);
145        }
146        if (access(path, R_OK)) {
147            continue;
148        }
149        /* we found a library matching this id/variant */
150        break;
151    }
152
153    status = -ENOENT;
154    if (i < HAL_VARIANT_KEYS_COUNT+1) {
155        /* load the module, if this fails, we're doomed, and we should not try
156         * to load a different variant. */
157        status = load(id, path, module);
158    }
159
160    return status;
161}
162