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