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