/****************************************************************************** * GPS HAL wrapper * wrapps around Samsung GPS Libary and replaces a faulty pointer to * a faulty function from Samsung that will cause the system_server * to crash. * * Copyright 2010 - Kolja Dummann * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * ******************************************************************************/ #include #include #include #include //#define ALOG_NDEBUG 0 #include #define ALOG_TAG "gps-wrapper" #include #define ORIGINAL_HAL_PATH "/system/lib/hw/vendor-gps.exynos4.so" static const AGpsRilInterface* oldAGPSRIL = NULL; static AGpsRilInterface newAGPSRIL; static const GpsInterface* originalGpsInterface = NULL; static GpsInterface newGpsInterface; /** * Load the file defined by the variant and if successful * return the dlopen handle and the hmi. * @return 0 = success, !0 = failure. */ static int load(const char *id, const char *path, const struct hw_module_t **pHmi) { int status; void *handle; struct hw_module_t *hmi; /* * load the symbols resolving undefined symbols before * dlopen returns. Since RTLD_GLOBAL is not or'd in with * RTLD_NOW the external symbols will not be global */ handle = dlopen(path, RTLD_NOW); if (handle == NULL) { char const *err_str = dlerror(); ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown"); status = -EINVAL; goto done; } /* Get the address of the struct hal_module_info. */ const char *sym = HAL_MODULE_INFO_SYM_AS_STR; hmi = (struct hw_module_t *)dlsym(handle, sym); if (hmi == NULL) { ALOGE("load: couldn't find symbol %s", sym); status = -EINVAL; goto done; } /* Check that the id matches */ if (strcmp(id, hmi->id) != 0) { ALOGE("load: id=%s != hmi->id=%s", id, hmi->id); status = -EINVAL; goto done; } hmi->dso = handle; /* success */ status = 0; done: if (status != 0) { hmi = NULL; if (handle != NULL) { dlclose(handle); handle = NULL; } } else { ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p", id, path, *pHmi, handle); } *pHmi = hmi; return status; } static void update_network_state_wrapper(int connected, int type, int roaming, const char* extra_info) { ALOGI("%s was called and saved your from a faulty implementation ;-)", __func__); } static const void* wrapper_get_extension(const char* name) { ALOGV("%s was called", __func__); if (!strcmp(name, AGPS_RIL_INTERFACE) && (oldAGPSRIL = originalGpsInterface->get_extension(name))) { ALOGV("%s AGPS_RIL_INTERFACE extension requested", __func__); /* use a wrapper to avoid calling samsungs faulty implemetation */ newAGPSRIL.size = sizeof(AGpsRilInterface); newAGPSRIL.init = oldAGPSRIL->init; newAGPSRIL.set_ref_location = oldAGPSRIL->set_ref_location; newAGPSRIL.set_set_id = oldAGPSRIL->set_set_id; newAGPSRIL.ni_message = oldAGPSRIL->ni_message; ALOGV("%s setting update_network_state_wrapper", __func__); newAGPSRIL.update_network_state = update_network_state_wrapper; return &newAGPSRIL; } return originalGpsInterface->get_extension(name); } /* HAL Methods */ const GpsInterface* gps_get_gps_interface(struct gps_device_t* dev) { hw_module_t* module; int err; ALOGV("%s was called", __func__); err = load(GPS_HARDWARE_MODULE_ID, ORIGINAL_HAL_PATH, (hw_module_t const**)&module); if (err == 0) { ALOGV("%s vendor lib loaded", __func__); hw_device_t* device; struct gps_device_t *gps_device; err = module->methods->open(module, GPS_HARDWARE_MODULE_ID, &device); if (err == 0) { ALOGV("%s got gps device", __func__); gps_device = (struct gps_device_t *)device; originalGpsInterface = gps_device->get_gps_interface(gps_device); ALOGV("%s device set", __func__); } } if(originalGpsInterface) { ALOGV("%s exposing callbacks", __func__); newGpsInterface.size = sizeof(GpsInterface); newGpsInterface.init = originalGpsInterface->init; newGpsInterface.start = originalGpsInterface->start; newGpsInterface.stop = originalGpsInterface->stop; newGpsInterface.cleanup = originalGpsInterface->cleanup; newGpsInterface.inject_time = originalGpsInterface->inject_time; newGpsInterface.inject_location = originalGpsInterface->inject_location; newGpsInterface.delete_aiding_data = originalGpsInterface->delete_aiding_data; newGpsInterface.set_position_mode = originalGpsInterface->set_position_mode; ALOGV("%s setting extension wrapper", __func__); newGpsInterface.get_extension = wrapper_get_extension; } ALOGV("%s done", __func__); return &newGpsInterface; } static int open_gps(const struct hw_module_t* module, char const* name, struct hw_device_t** device) { struct gps_device_t *dev = malloc(sizeof(struct gps_device_t)); memset(dev, 0, sizeof(*dev)); ALOGV("%s was called", __func__); dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = (struct hw_module_t*)module; dev->get_gps_interface = gps_get_gps_interface; *device = (struct hw_device_t*)dev; return 0; } static struct hw_module_methods_t gps_module_methods = { .open = open_gps }; const struct hw_module_t HAL_MODULE_INFO_SYM = { .tag = HARDWARE_MODULE_TAG, .version_major = 1, .version_minor = 0, .id = GPS_HARDWARE_MODULE_ID, .name = "GPS HAL Wrapper Module", .author = "Kolja Dummann", .methods = &gps_module_methods, };