OSDN Git Service

Merge "Clarify that reserved function pointers has to be set to null" into oc-dev
[android-x86/hardware-libhardware.git] / hardware.c
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 #include <stdio.h>
27 #include <unistd.h>
28
29 #define LOG_TAG "HAL"
30 #include <log/log.h>
31
32 /** Base path of the hal modules */
33 #if defined(__LP64__)
34 #define HAL_LIBRARY_PATH1 "/system/lib64/hw"
35 #define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"
36 #define HAL_LIBRARY_PATH3 "/odm/lib64/hw"
37 #else
38 #define HAL_LIBRARY_PATH1 "/system/lib/hw"
39 #define HAL_LIBRARY_PATH2 "/vendor/lib/hw"
40 #define HAL_LIBRARY_PATH3 "/odm/lib/hw"
41 #endif
42
43 /**
44  * There are a set of variant filename for modules. The form of the filename
45  * is "<MODULE_ID>.variant.so" so for the led module the Dream variants 
46  * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be:
47  *
48  * led.trout.so
49  * led.msm7k.so
50  * led.ARMV6.so
51  * led.default.so
52  */
53
54 static const char *variant_keys[] = {
55     "ro.hardware",  /* This goes first so that it can pick up a different
56                        file on the emulator. */
57     "ro.product.board",
58     "ro.board.platform",
59     "ro.arch"
60 };
61
62 static const int HAL_VARIANT_KEYS_COUNT =
63     (sizeof(variant_keys)/sizeof(variant_keys[0]));
64
65 /**
66  * Load the file defined by the variant and if successful
67  * return the dlopen handle and the hmi.
68  * @return 0 = success, !0 = failure.
69  */
70 static int load(const char *id,
71         const char *path,
72         const struct hw_module_t **pHmi)
73 {
74     int status = -EINVAL;
75     void *handle = NULL;
76     struct hw_module_t *hmi = NULL;
77
78     /*
79      * load the symbols resolving undefined symbols before
80      * dlopen returns. Since RTLD_GLOBAL is not or'd in with
81      * RTLD_NOW the external symbols will not be global
82      */
83     handle = dlopen(path, RTLD_NOW);
84     if (handle == NULL) {
85         char const *err_str = dlerror();
86         ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown");
87         status = -EINVAL;
88         goto done;
89     }
90
91     /* Get the address of the struct hal_module_info. */
92     const char *sym = HAL_MODULE_INFO_SYM_AS_STR;
93     hmi = (struct hw_module_t *)dlsym(handle, sym);
94     if (hmi == NULL) {
95         ALOGE("load: couldn't find symbol %s", sym);
96         status = -EINVAL;
97         goto done;
98     }
99
100     /* Check that the id matches */
101     if (strcmp(id, hmi->id) != 0) {
102         ALOGE("load: id=%s != hmi->id=%s", id, hmi->id);
103         status = -EINVAL;
104         goto done;
105     }
106
107     hmi->dso = handle;
108
109     /* success */
110     status = 0;
111
112     done:
113     if (status != 0) {
114         hmi = NULL;
115         if (handle != NULL) {
116             dlclose(handle);
117             handle = NULL;
118         }
119     } else {
120         ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p",
121                 id, path, *pHmi, handle);
122     }
123
124     *pHmi = hmi;
125
126     return status;
127 }
128
129 /*
130  * Check if a HAL with given name and subname exists, if so return 0, otherwise
131  * otherwise return negative.  On success path will contain the path to the HAL.
132  */
133 static int hw_module_exists(char *path, size_t path_len, const char *name,
134                             const char *subname)
135 {
136     snprintf(path, path_len, "%s/%s.%s.so",
137              HAL_LIBRARY_PATH3, name, subname);
138     if (access(path, R_OK) == 0)
139         return 0;
140
141     snprintf(path, path_len, "%s/%s.%s.so",
142              HAL_LIBRARY_PATH2, name, subname);
143     if (access(path, R_OK) == 0)
144         return 0;
145
146     snprintf(path, path_len, "%s/%s.%s.so",
147              HAL_LIBRARY_PATH1, name, subname);
148     if (access(path, R_OK) == 0)
149         return 0;
150
151     return -ENOENT;
152 }
153
154 int hw_get_module_by_class(const char *class_id, const char *inst,
155                            const struct hw_module_t **module)
156 {
157     int i = 0;
158     char prop[PATH_MAX] = {0};
159     char path[PATH_MAX] = {0};
160     char name[PATH_MAX] = {0};
161     char prop_name[PATH_MAX] = {0};
162
163
164     if (inst)
165         snprintf(name, PATH_MAX, "%s.%s", class_id, inst);
166     else
167         strlcpy(name, class_id, PATH_MAX);
168
169     /*
170      * Here we rely on the fact that calling dlopen multiple times on
171      * the same .so will simply increment a refcount (and not load
172      * a new copy of the library).
173      * We also assume that dlopen() is thread-safe.
174      */
175
176     /* First try a property specific to the class and possibly instance */
177     snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name);
178     if (property_get(prop_name, prop, NULL) > 0) {
179         if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
180             goto found;
181         }
182     }
183
184     /* Loop through the configuration variants looking for a module */
185     for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) {
186         if (property_get(variant_keys[i], prop, NULL) == 0) {
187             continue;
188         }
189         if (hw_module_exists(path, sizeof(path), name, prop) == 0) {
190             goto found;
191         }
192     }
193
194     /* Nothing found, try the default */
195     if (hw_module_exists(path, sizeof(path), name, "default") == 0) {
196         goto found;
197     }
198
199     return -ENOENT;
200
201 found:
202     /* load the module, if this fails, we're doomed, and we should not try
203      * to load a different variant. */
204     return load(class_id, path, module);
205 }
206
207 int hw_get_module(const char *id, const struct hw_module_t **module)
208 {
209     return hw_get_module_by_class(id, NULL, module);
210 }