hardware.c revision 8232b50d981ce9c584fc1a4af82dae5e70e6ce52
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 44#define HAL_DEFAULT_VARIANT "default" 45static const char *variant_keys[] = { 46 "ro.hardware", /* This goes first so that it can pick up a different 47 file on the emulator. */ 48 "ro.product.board", 49 "ro.board.platform", 50 "ro.arch" 51}; 52#define HAL_VARIANT_KEYS_COUNT (sizeof(variant_keys)/sizeof(variant_keys[0])) 53 54/** 55 * Load the file defined by the variant and if succesfull 56 * return the dlopen handle and the hmi. 57 * @return 0 = success, !0 = failure. 58 */ 59static int load(const char *id, 60 const char *variant, 61 const struct hw_module_t **pHmi) 62{ 63 int status; 64 void *handle; 65 const struct hw_module_t *hmi; 66 char path[PATH_MAX]; 67 68 /* Construct the path. */ 69 snprintf(path, sizeof(path), "%s/%s.%s.so", HAL_LIBRARY_PATH, id, variant); 70 71 LOGV("load: E id=%s path=%s", id, path); 72 73 /* 74 * load the symbols resolving undefined symbols before 75 * dlopen returns. Since RTLD_GLOBAL is not or'd in with 76 * RTLD_NOW the external symbols will not be global 77 */ 78 handle = dlopen(path, RTLD_NOW); 79 if (handle == NULL) { 80 char const *err_str = dlerror(); 81 LOGW("load: module=%s error=%s", path, err_str); 82 status = -EINVAL; 83 goto done; 84 } 85 86 /* Get the address of the struct hal_module_info. */ 87 const char *sym = HAL_MODULE_INFO_SYM_AS_STR; 88 hmi = (const struct hw_module_t *)dlsym(handle, sym); 89 if (hmi == NULL) { 90 char const *err_str = dlerror(); 91 LOGE("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 LOGE("load: id=%s != hmi->id=%s", id, hmi->id); 99 status = -EINVAL; 100 goto done; 101 } 102 103 /* success */ 104 status = 0; 105 106done: 107 if (status != 0) { 108 hmi = NULL; 109 if (handle != NULL) { 110 dlclose(handle); 111 handle = NULL; 112 } 113 } 114 115 *pHmi = hmi; 116 117 LOGV("load: X id=%s path=%s hmi=%p handle=%p status=%d", 118 id, path, *pHmi, handle, status); 119 return status; 120} 121 122int hw_get_module(const char *id, const struct hw_module_t **module) 123{ 124 int status; 125 int i; 126 const struct hw_module_t *hmi = NULL; 127 char prop[PATH_MAX]; 128 129 /* 130 * Here we rely on the fact that calling dlopen multiple times on 131 * the same .so will simply increment a refcount (and not load 132 * a new copy of the library). 133 * We also assume that dlopen() is thread-safe. 134 */ 135 136 LOGV("hal_module_info_get: Load module id=%s", id); 137 138 status = -EINVAL; 139 140 /* Loop through the configuration variants looking for a module */ 141 for (i = 0; (status != 0) && (i < HAL_VARIANT_KEYS_COUNT); i++) { 142 if (property_get(variant_keys[i], prop, NULL) == 0) { 143 continue; 144 } 145 status = load(id, prop, &hmi); 146 } 147 148 /* Try default */ 149 if (status != 0) { 150 status = load(id, HAL_DEFAULT_VARIANT, &hmi); 151 } 152 153 *module = hmi; 154 LOGV("hal_module_info_get: X id=%s hmi=%p status=%d", id, hmi, status); 155 156 return status; 157} 158