Home | History | Annotate | Download | only in libhardware
      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