| /* |
| * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved. |
| * Not a Contribution |
| */ |
| /* |
| * Copyright (C) 2016 The Android Open Source Project |
| * |
| * 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. |
| */ |
| |
| #define LOG_TAG "LocSvc_GnssInterface" |
| #define LOG_NDEBUG 0 |
| |
| #include <fstream> |
| #include <log_util.h> |
| #include <dlfcn.h> |
| #include <cutils/properties.h> |
| #include "Gnss.h" |
| #include <LocationUtil.h> |
| #include "battery_listener.h" |
| #include "loc_misc_utils.h" |
| |
| typedef const GnssInterface* (getLocationInterface)(); |
| |
| namespace android { |
| namespace hardware { |
| namespace gnss { |
| namespace V1_0 { |
| namespace implementation { |
| |
| static sp<Gnss> sGnss; |
| void Gnss::GnssDeathRecipient::serviceDied(uint64_t cookie, const wp<IBase>& who) { |
| LOC_LOGE("%s] service died. cookie: %llu, who: %p", |
| __FUNCTION__, static_cast<unsigned long long>(cookie), &who); |
| if (mGnss != nullptr) { |
| mGnss->getGnssInterface()->resetNetworkInfo(); |
| mGnss->stop(); |
| mGnss->cleanup(); |
| } |
| } |
| |
| void location_on_battery_status_changed(bool charging) { |
| LOC_LOGd("battery status changed to %s charging", charging ? "" : "not "); |
| if (sGnss != nullptr) { |
| sGnss->getGnssInterface()->updateBatteryStatus(charging); |
| } |
| } |
| Gnss::Gnss() { |
| ENTRY_LOG_CALLFLOW(); |
| sGnss = this; |
| // initilize gnss interface at first in case needing notify battery status |
| sGnss->getGnssInterface()->initialize(); |
| // register health client to listen on battery change |
| loc_extn_battery_properties_listener_init(location_on_battery_status_changed); |
| // clear pending GnssConfig |
| memset(&mPendingConfig, 0, sizeof(GnssConfig)); |
| |
| mGnssDeathRecipient = new GnssDeathRecipient(this); |
| } |
| |
| Gnss::~Gnss() { |
| ENTRY_LOG_CALLFLOW(); |
| if (mApi != nullptr) { |
| mApi->destroy(); |
| mApi = nullptr; |
| } |
| sGnss = nullptr; |
| } |
| |
| GnssAPIClient* Gnss::getApi() { |
| if (mApi == nullptr && (mGnssCbIface != nullptr || mGnssNiCbIface != nullptr)) { |
| mApi = new GnssAPIClient(mGnssCbIface, mGnssNiCbIface); |
| if (mApi == nullptr) { |
| LOC_LOGE("%s] faild to create GnssAPIClient", __FUNCTION__); |
| return mApi; |
| } |
| |
| if (mPendingConfig.size == sizeof(GnssConfig)) { |
| // we have pending GnssConfig |
| mApi->gnssConfigurationUpdate(mPendingConfig); |
| // clear size to invalid mPendingConfig |
| mPendingConfig.size = 0; |
| if (mPendingConfig.assistanceServer.hostName != nullptr) { |
| free((void*)mPendingConfig.assistanceServer.hostName); |
| } |
| } |
| } |
| if (mApi == nullptr) { |
| LOC_LOGW("%s] GnssAPIClient is not ready", __FUNCTION__); |
| } |
| return mApi; |
| } |
| |
| const GnssInterface* Gnss::getGnssInterface() { |
| static bool getGnssInterfaceFailed = false; |
| if (nullptr == mGnssInterface && !getGnssInterfaceFailed) { |
| void * libHandle = nullptr; |
| getLocationInterface* getter = (getLocationInterface*) |
| dlGetSymFromLib(libHandle, "libgnss.so", "getGnssInterface"); |
| |
| if (nullptr == getter) { |
| getGnssInterfaceFailed = true; |
| } else { |
| mGnssInterface = (GnssInterface*)(*getter)(); |
| } |
| } |
| return mGnssInterface; |
| } |
| |
| Return<bool> Gnss::setCallback(const sp<V1_0::IGnssCallback>& callback) { |
| ENTRY_LOG_CALLFLOW(); |
| if (mGnssCbIface != nullptr) { |
| mGnssCbIface->unlinkToDeath(mGnssDeathRecipient); |
| } |
| mGnssCbIface = callback; |
| if (mGnssCbIface != nullptr) { |
| mGnssCbIface->linkToDeath(mGnssDeathRecipient, 0 /*cookie*/); |
| } |
| |
| GnssAPIClient* api = getApi(); |
| if (api != nullptr) { |
| api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface); |
| api->gnssEnable(LOCATION_TECHNOLOGY_TYPE_GNSS); |
| api->requestCapabilities(); |
| } |
| return true; |
| } |
| |
| Return<bool> Gnss::setGnssNiCb(const sp<IGnssNiCallback>& callback) { |
| ENTRY_LOG_CALLFLOW(); |
| mGnssNiCbIface = callback; |
| GnssAPIClient* api = getApi(); |
| if (api != nullptr) { |
| api->gnssUpdateCallbacks(mGnssCbIface, mGnssNiCbIface); |
| } |
| return true; |
| } |
| |
| Return<bool> Gnss::updateConfiguration(GnssConfig& gnssConfig) { |
| ENTRY_LOG_CALLFLOW(); |
| GnssAPIClient* api = getApi(); |
| if (api) { |
| api->gnssConfigurationUpdate(gnssConfig); |
| } else if (gnssConfig.flags != 0) { |
| // api is not ready yet, update mPendingConfig with gnssConfig |
| mPendingConfig.size = sizeof(GnssConfig); |
| |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_GPS_LOCK_VALID_BIT; |
| mPendingConfig.gpsLock = gnssConfig.gpsLock; |
| } |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_VERSION_VALID_BIT; |
| mPendingConfig.suplVersion = gnssConfig.suplVersion; |
| } |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SET_ASSISTANCE_DATA_VALID_BIT; |
| mPendingConfig.assistanceServer.size = sizeof(GnssConfigSetAssistanceServer); |
| mPendingConfig.assistanceServer.type = gnssConfig.assistanceServer.type; |
| if (mPendingConfig.assistanceServer.hostName != nullptr) { |
| free((void*)mPendingConfig.assistanceServer.hostName); |
| mPendingConfig.assistanceServer.hostName = |
| strdup(gnssConfig.assistanceServer.hostName); |
| } |
| mPendingConfig.assistanceServer.port = gnssConfig.assistanceServer.port; |
| } |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPP_PROFILE_VALID_BIT; |
| mPendingConfig.lppProfile = gnssConfig.lppProfile; |
| } |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_CONTROL_PLANE_VALID_BIT; |
| mPendingConfig.lppeControlPlaneMask = gnssConfig.lppeControlPlaneMask; |
| } |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_LPPE_USER_PLANE_VALID_BIT; |
| mPendingConfig.lppeUserPlaneMask = gnssConfig.lppeUserPlaneMask; |
| } |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_AGLONASS_POSITION_PROTOCOL_VALID_BIT; |
| mPendingConfig.aGlonassPositionProtocolMask = gnssConfig.aGlonassPositionProtocolMask; |
| } |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_EM_PDN_FOR_EM_SUPL_VALID_BIT; |
| mPendingConfig.emergencyPdnForEmergencySupl = gnssConfig.emergencyPdnForEmergencySupl; |
| } |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_EM_SERVICES_BIT; |
| mPendingConfig.suplEmergencyServices = gnssConfig.suplEmergencyServices; |
| } |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_SUPL_MODE_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_SUPL_MODE_BIT; |
| mPendingConfig.suplModeMask = gnssConfig.suplModeMask; |
| } |
| if (gnssConfig.flags & GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT) { |
| mPendingConfig.flags |= GNSS_CONFIG_FLAGS_BLACKLISTED_SV_IDS_BIT; |
| mPendingConfig.blacklistedSvIds = gnssConfig.blacklistedSvIds; |
| } |
| } |
| return true; |
| } |
| |
| Return<bool> Gnss::start() { |
| ENTRY_LOG_CALLFLOW(); |
| bool retVal = false; |
| GnssAPIClient* api = getApi(); |
| if (api) { |
| retVal = api->gnssStart(); |
| } |
| return retVal; |
| } |
| |
| Return<bool> Gnss::stop() { |
| ENTRY_LOG_CALLFLOW(); |
| bool retVal = false; |
| GnssAPIClient* api = getApi(); |
| if (api) { |
| retVal = api->gnssStop(); |
| } |
| return retVal; |
| } |
| |
| Return<void> Gnss::cleanup() { |
| ENTRY_LOG_CALLFLOW(); |
| |
| if (mApi != nullptr) { |
| mApi->gnssDisable(); |
| } |
| |
| return Void(); |
| } |
| |
| Return<bool> Gnss::injectLocation(double latitudeDegrees, |
| double longitudeDegrees, |
| float accuracyMeters) { |
| ENTRY_LOG_CALLFLOW(); |
| const GnssInterface* gnssInterface = getGnssInterface(); |
| if (nullptr != gnssInterface) { |
| gnssInterface->injectLocation(latitudeDegrees, longitudeDegrees, accuracyMeters); |
| return true; |
| } else { |
| return false; |
| } |
| } |
| |
| Return<bool> Gnss::injectTime(int64_t timeMs, int64_t timeReferenceMs, |
| int32_t uncertaintyMs) { |
| ENTRY_LOG_CALLFLOW(); |
| const GnssInterface* gnssInterface = getGnssInterface(); |
| if ((nullptr != gnssInterface) && (gnssInterface->isSS5HWEnabled())) { |
| gnssInterface->injectTime(timeMs, timeReferenceMs, uncertaintyMs); |
| } |
| return true; |
| } |
| |
| Return<void> Gnss::deleteAidingData(V1_0::IGnss::GnssAidingData aidingDataFlags) { |
| ENTRY_LOG_CALLFLOW(); |
| GnssAPIClient* api = getApi(); |
| if (api) { |
| api->gnssDeleteAidingData(aidingDataFlags); |
| } |
| return Void(); |
| } |
| |
| Return<bool> Gnss::setPositionMode(V1_0::IGnss::GnssPositionMode mode, |
| V1_0::IGnss::GnssPositionRecurrence recurrence, |
| uint32_t minIntervalMs, |
| uint32_t preferredAccuracyMeters, |
| uint32_t preferredTimeMs) { |
| ENTRY_LOG_CALLFLOW(); |
| bool retVal = false; |
| GnssAPIClient* api = getApi(); |
| if (api) { |
| retVal = api->gnssSetPositionMode(mode, recurrence, minIntervalMs, |
| preferredAccuracyMeters, preferredTimeMs); |
| } |
| return retVal; |
| } |
| |
| Return<sp<V1_0::IAGnss>> Gnss::getExtensionAGnss() { |
| ENTRY_LOG_CALLFLOW(); |
| mAGnssIface = new AGnss(this); |
| return mAGnssIface; |
| } |
| |
| Return<sp<V1_0::IGnssNi>> Gnss::getExtensionGnssNi() { |
| ENTRY_LOG_CALLFLOW(); |
| mGnssNi = new GnssNi(this); |
| return mGnssNi; |
| } |
| |
| Return<sp<V1_0::IGnssMeasurement>> Gnss::getExtensionGnssMeasurement() { |
| ENTRY_LOG_CALLFLOW(); |
| if (mGnssMeasurement == nullptr) |
| mGnssMeasurement = new GnssMeasurement(); |
| return mGnssMeasurement; |
| } |
| |
| Return<sp<V1_0::IGnssConfiguration>> Gnss::getExtensionGnssConfiguration() { |
| ENTRY_LOG_CALLFLOW(); |
| mGnssConfig = new GnssConfiguration(this); |
| return mGnssConfig; |
| } |
| |
| Return<sp<V1_0::IGnssGeofencing>> Gnss::getExtensionGnssGeofencing() { |
| ENTRY_LOG_CALLFLOW(); |
| mGnssGeofencingIface = new GnssGeofencing(); |
| return mGnssGeofencingIface; |
| } |
| |
| Return<sp<V1_0::IGnssBatching>> Gnss::getExtensionGnssBatching() { |
| mGnssBatching = new GnssBatching(); |
| return mGnssBatching; |
| } |
| |
| Return<sp<V1_0::IGnssDebug>> Gnss::getExtensionGnssDebug() { |
| ENTRY_LOG_CALLFLOW(); |
| mGnssDebug = new GnssDebug(this); |
| return mGnssDebug; |
| } |
| |
| Return<sp<V1_0::IAGnssRil>> Gnss::getExtensionAGnssRil() { |
| mGnssRil = new AGnssRil(this); |
| return mGnssRil; |
| } |
| |
| IGnss* HIDL_FETCH_IGnss(const char* hal) { |
| ENTRY_LOG_CALLFLOW(); |
| IGnss* iface = nullptr; |
| iface = new Gnss(); |
| if (iface == nullptr) { |
| LOC_LOGE("%s]: failed to get %s", __FUNCTION__, hal); |
| } |
| return iface; |
| } |
| |
| } // namespace implementation |
| } // namespace V1_0 |
| } // namespace gnss |
| } // namespace hardware |
| } // namespace android |