diff options
author | Saurabh Srivastava <ssrivast@codeaurora.org> | 2017-02-03 00:46:48 +0530 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2017-02-28 16:59:38 -0800 |
commit | 5fecc1979b38724fb54d824ddadc61ba35475743 (patch) | |
tree | d9273f6964b8ebbfa0d34358302959f2c98e72d6 | |
parent | 52b413eb442e184a22d508f98af5e7f30e6952a5 (diff) | |
download | gps-5fecc1979b38724fb54d824ddadc61ba35475743.tar.gz |
Adding ATL call flow to new Loc API interface
Re-designed the ATL call flow, to fit along with
updated Location API.
Change-Id: If22e672d1c233c55b6b52107be7169b3036d9a3e
CRs-fixed: 1112712
-rw-r--r-- | android/AGnss.cpp | 65 | ||||
-rw-r--r-- | android/AGnss.h | 22 | ||||
-rw-r--r-- | gnss/Agps.cpp | 963 | ||||
-rw-r--r-- | gnss/Agps.h | 446 | ||||
-rw-r--r-- | gnss/Android.mk | 3 | ||||
-rw-r--r-- | gnss/GnssAdapter.cpp | 335 | ||||
-rw-r--r-- | gnss/GnssAdapter.h | 20 | ||||
-rw-r--r-- | gnss/location_gnss.cpp | 37 | ||||
-rw-r--r-- | location/location_interface.h | 4 |
9 files changed, 1879 insertions, 16 deletions
diff --git a/android/AGnss.cpp b/android/AGnss.cpp index 3b40e60..c497ed4 100644 --- a/android/AGnss.cpp +++ b/android/AGnss.cpp @@ -23,6 +23,7 @@ #include <log_util.h> #include "Gnss.h" #include "AGnss.h" +#include <gps_extended_c.h> namespace android { namespace hardware { @@ -30,9 +31,73 @@ namespace gnss { namespace V1_0 { namespace implementation { +sp<IAGnssCallback> AGnss::sAGnssCbIface = nullptr; + AGnss::AGnss(Gnss* gnss) : mGnss(gnss) { } +void AGnss::agnssStatusIpV4Cb(IAGnssCallback::AGnssStatusIpV4 status){ + + sAGnssCbIface->agnssStatusIpV4Cb(status); +} + +Return<void> AGnss::setCallback(const sp<IAGnssCallback>& callback) { + + if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){ + LOC_LOGE("Null GNSS interface"); + return Void(); + } + + // Save the interface + sAGnssCbIface = callback; + + mGnss->getGnssInterface()->agpsInit((void*)agnssStatusIpV4Cb); + return Void(); +} + +Return<bool> AGnss::dataConnClosed() { + + if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){ + LOC_LOGE("Null GNSS interface"); + return false; + } + + mGnss->getGnssInterface()->agpsDataConnClosed(LOC_AGPS_TYPE_SUPL); + return true; +} + +Return<bool> AGnss::dataConnFailed() { + + if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){ + LOC_LOGE("Null GNSS interface"); + return false; + } + + mGnss->getGnssInterface()->agpsDataConnFailed(LOC_AGPS_TYPE_SUPL); + return true; +} + +Return<bool> AGnss::dataConnOpen(const hidl_string& apn, + IAGnss::ApnIpType apnIpType) { + + if(mGnss == nullptr || mGnss->getGnssInterface() == nullptr){ + LOC_LOGE("Null GNSS interface"); + return false; + } + + /* Validate */ + if(apn.empty()){ + LOC_LOGE("Invalid APN"); + return false; + } + + LOC_LOGD("dataConnOpen APN name = [%s]", apn.c_str()); + + mGnss->getGnssInterface()->agpsDataConnOpen( + LOC_AGPS_TYPE_SUPL, apn.c_str(), apn.size(), (int)apnIpType); + return true; +} + Return<bool> AGnss::setServer(IAGnssCallback::AGnssType type, const hidl_string& hostname, int32_t port) { diff --git a/android/AGnss.h b/android/AGnss.h index 54775c1..f4216b0 100644 --- a/android/AGnss.h +++ b/android/AGnss.h @@ -40,35 +40,31 @@ using ::android::sp; struct Gnss; struct AGnss : public IAGnss { + AGnss(Gnss* gnss); ~AGnss() = default; /* * Methods from ::android::hardware::gnss::V1_0::IAGnss interface follow. * These declarations were generated from IAGnss.hal. */ - inline Return<void> setCallback(const sp<IAGnssCallback>& /*callback*/) override { - return Void(); - } + Return<void> setCallback(const sp<IAGnssCallback>& callback) override; - inline Return<bool> dataConnClosed() override { - return false; - } + Return<bool> dataConnClosed() override; - inline Return<bool> dataConnFailed() override { - return false; - } + Return<bool> dataConnFailed() override; - inline Return<bool> dataConnOpen(const hidl_string& /*apn*/, - IAGnss::ApnIpType /*apnIpType*/) override { - return false; - } + Return<bool> dataConnOpen(const hidl_string& apn, + IAGnss::ApnIpType apnIpType) override; Return<bool> setServer(IAGnssCallback::AGnssType type, const hidl_string& hostname, int32_t port) override; + /* Data call setup callback passed down to GNSS HAL implementation */ + static void agnssStatusIpV4Cb(IAGnssCallback::AGnssStatusIpV4 status); private: Gnss* mGnss = nullptr; + static sp<IAGnssCallback> sAGnssCbIface; }; } // namespace implementation diff --git a/gnss/Agps.cpp b/gnss/Agps.cpp new file mode 100644 index 0000000..aacd9da --- /dev/null +++ b/gnss/Agps.cpp @@ -0,0 +1,963 @@ +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation, nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#define LOG_TAG "LocSvc_Agps" + +#include <Agps.h> +#include <platform_lib_includes.h> +#include <ContextBase.h> +#include <loc_timer.h> + +/* -------------------------------------------------------------------- + * AGPS State Machine Methods + * -------------------------------------------------------------------*/ +void AgpsStateMachine::processAgpsEvent(AgpsEvent event){ + + LOC_LOGD("processAgpsEvent(): SM %p, Event %d, State %d", + this, event, mState); + + switch (event){ + + case AGPS_EVENT_SUBSCRIBE: + processAgpsEventSubscribe(); + break; + + case AGPS_EVENT_UNSUBSCRIBE: + processAgpsEventUnsubscribe(); + break; + + case AGPS_EVENT_GRANTED: + processAgpsEventGranted(); + break; + + case AGPS_EVENT_RELEASED: + processAgpsEventReleased(); + break; + + case AGPS_EVENT_DENIED: + processAgpsEventDenied(); + break; + + default: + LOC_LOGE("Invalid Loc Agps Event"); + } +} + +void AgpsStateMachine::processAgpsEventSubscribe(){ + + switch (mState){ + + case AGPS_STATE_RELEASED: + /* Add subscriber to list + * No notifications until we get RSRC_GRANTED */ + addSubscriber(mCurrentSubscriber); + + /* Send data request + * The if condition below is added so that if the data call setup + * fails for DS State Machine, we want to retry in released state. + * for Agps State Machine, sendRsrcRequest() will always return + * success. */ + if(requestOrReleaseDataConn(true) == 0){ + // If data request successful, move to pending state + transitionState(AGPS_STATE_PENDING); + } + break; + + case AGPS_STATE_PENDING: + /* Already requested for data connection, + * do nothing until we get RSRC_GRANTED event; + * Just add this subscriber to the list, for notifications */ + addSubscriber(mCurrentSubscriber); + break; + + case AGPS_STATE_ACQUIRED: + /* We already have the data connection setup, + * Notify current subscriber with GRANTED event, + * And add it to the subscriber list for further notifications. */ + notifyEventToSubscriber(AGPS_EVENT_GRANTED, mCurrentSubscriber, false); + addSubscriber(mCurrentSubscriber); + break; + + case AGPS_STATE_RELEASING: + addSubscriber(mCurrentSubscriber); + break; + + default: + LOC_LOGE("Invalid state: %d", mState); + } +} + +void AgpsStateMachine::processAgpsEventUnsubscribe(){ + + switch (mState){ + + case AGPS_STATE_RELEASED: + notifyEventToSubscriber( + AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, false); + break; + + case AGPS_STATE_PENDING: + case AGPS_STATE_ACQUIRED: + /* If the subscriber wishes to wait for connection close, + * before being removed from list, move to inactive state + * and notify */ + if(mCurrentSubscriber->mWaitForCloseComplete){ + mCurrentSubscriber->mIsInactive = true; + notifyEventToSubscriber( + AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, false); + } + else{ + /* Notify only current subscriber and then delete it from + * subscriberList */ + notifyEventToSubscriber( + AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, true); + } + + /* If no subscribers in list, release data connection */ + if(mSubscriberList.empty()){ + transitionState(AGPS_STATE_RELEASED); + requestOrReleaseDataConn(false); + } + /* Some subscribers in list, but all inactive; + * Release data connection */ + else if(!anyActiveSubscribers()){ + transitionState(AGPS_STATE_RELEASING); + requestOrReleaseDataConn(false); + } + break; + + case AGPS_STATE_RELEASING: + /* If the subscriber wishes to wait for connection close, + * before being removed from list, move to inactive state + * and notify */ + if(mCurrentSubscriber->mWaitForCloseComplete){ + mCurrentSubscriber->mIsInactive = true; + notifyEventToSubscriber( + AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, false); + } + else{ + /* Notify only current subscriber and then delete it from + * subscriberList */ + notifyEventToSubscriber( + AGPS_EVENT_UNSUBSCRIBE, mCurrentSubscriber, true); + } + + /* If no subscribers in list, just move the state. + * Request for releasing data connection should already have been + * sent */ + if(mSubscriberList.empty()){ + transitionState(AGPS_STATE_RELEASED); + } + break; + + default: + LOC_LOGE("Invalid state: %d", mState); + } +} + +void AgpsStateMachine::processAgpsEventGranted(){ + + switch (mState){ + + case AGPS_STATE_RELEASED: + case AGPS_STATE_ACQUIRED: + case AGPS_STATE_RELEASING: + LOC_LOGE("Unexpected event GRANTED in state %d", mState); + break; + + case AGPS_STATE_PENDING: + // Move to acquired state + transitionState(AGPS_STATE_ACQUIRED); + notifyAllSubscribers( + AGPS_EVENT_GRANTED, false, + AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS); + break; + + default: + LOC_LOGE("Invalid state: %d", mState); + } +} + +void AgpsStateMachine::processAgpsEventReleased(){ + + switch (mState){ + + case AGPS_STATE_RELEASED: + LOC_LOGE("Unexpected event RELEASED in state %d", mState); + break; + + case AGPS_STATE_ACQUIRED: + /* Force release received */ + LOC_LOGW("Force RELEASED event in ACQUIRED state"); + transitionState(AGPS_STATE_RELEASED); + notifyAllSubscribers( + AGPS_EVENT_RELEASED, true, + AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS); + break; + + case AGPS_STATE_RELEASING: + /* Notify all inactive subscribers about the event */ + notifyAllSubscribers( + AGPS_EVENT_RELEASED, true, + AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS); + + /* If we have active subscribers now, they must be waiting for + * data conn setup */ + if(anyActiveSubscribers()){ + transitionState(AGPS_STATE_PENDING); + requestOrReleaseDataConn(true); + } + /* No active subscribers, move to released state */ + else{ + transitionState(AGPS_STATE_RELEASED); + } + break; + + case AGPS_STATE_PENDING: + /* NOOP */ + break; + + default: + LOC_LOGE("Invalid state: %d", mState); + } +} + +void AgpsStateMachine::processAgpsEventDenied(){ + + switch (mState){ + + case AGPS_STATE_RELEASED: + LOC_LOGE("Unexpected event DENIED in state %d", mState); + break; + + case AGPS_STATE_ACQUIRED: + /* NOOP */ + break; + + case AGPS_STATE_RELEASING: + /* Notify all inactive subscribers about the event */ + notifyAllSubscribers( + AGPS_EVENT_RELEASED, true, + AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS); + + /* If we have active subscribers now, they must be waiting for + * data conn setup */ + if(anyActiveSubscribers()){ + transitionState(AGPS_STATE_PENDING); + requestOrReleaseDataConn(true); + } + /* No active subscribers, move to released state */ + else{ + transitionState(AGPS_STATE_RELEASED); + } + break; + + case AGPS_STATE_PENDING: + transitionState(AGPS_STATE_RELEASED); + notifyAllSubscribers( + AGPS_EVENT_DENIED, true, + AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS); + break; + + default: + LOC_LOGE("Invalid state: %d", mState); + } +} + +/* Request or Release data connection + * bool request : + * true = Request data connection + * false = Release data connection */ +int AgpsStateMachine::requestOrReleaseDataConn(bool request){ + + AgpsFrameworkInterface::AGnssStatusIpV4 nifRequest; + memset(&nifRequest, 0, sizeof(nifRequest)); + + nifRequest.type = (AgpsFrameworkInterface::AGnssType)mAgpsType; + + if(request){ + LOC_LOGD("AGPS Data Conn Request"); + nifRequest.status = (AgpsFrameworkInterface::AGnssStatusValue) + LOC_GPS_REQUEST_AGPS_DATA_CONN; + } + else{ + LOC_LOGD("AGPS Data Conn Release"); + nifRequest.status = (AgpsFrameworkInterface::AGnssStatusValue) + LOC_GPS_RELEASE_AGPS_DATA_CONN; + } + + mAgpsManager->mFrameworkStatusV4Cb(nifRequest); + return 0; +} + +void AgpsStateMachine::notifyAllSubscribers( + AgpsEvent event, bool deleteSubscriberPostNotify, + AgpsNotificationType notificationType){ + + LOC_LOGD("notifyAllSubscribers(): " + "SM %p, Event %d Delete %d Notification Type %d", + this, event, deleteSubscriberPostNotify, notificationType); + + std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); + while ( it != mSubscriberList.end() ){ + + AgpsSubscriber* subscriber = *it; + + if(notificationType == AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS || + (notificationType == AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS && + subscriber->mIsInactive) || + (notificationType == AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS && + !subscriber->mIsInactive)) { + + /* Deleting via this call would require another traversal + * through subscriber list, inefficient; hence pass in false*/ + notifyEventToSubscriber(event, subscriber, false); + + if(deleteSubscriberPostNotify){ + it = mSubscriberList.erase(it); + delete subscriber; + } else{ + it++; + } + } else{ + it++; + } + } +} + +void AgpsStateMachine::notifyEventToSubscriber( + AgpsEvent event, AgpsSubscriber* subscriberToNotify, + bool deleteSubscriberPostNotify) { + + LOC_LOGD("notifyEventToSubscriber(): " + "SM %p, Event %d Subscriber %p Delete %d", + this, event, subscriberToNotify, deleteSubscriberPostNotify); + + switch (event){ + + case AGPS_EVENT_GRANTED: + mAgpsManager->mAtlOpenStatusCb( + subscriberToNotify->mConnHandle, 1, getAPN(), + getBearer(), mAgpsType); + break; + + case AGPS_EVENT_DENIED: + mAgpsManager->mAtlOpenStatusCb( + subscriberToNotify->mConnHandle, 0, getAPN(), + getBearer(), mAgpsType); + break; + + case AGPS_EVENT_UNSUBSCRIBE: + case AGPS_EVENT_RELEASED: + mAgpsManager->mAtlCloseStatusCb(subscriberToNotify->mConnHandle, 1); + break; + + default: + LOC_LOGE("Invalid event %d", event); + } + + /* Search this subscriber in list and delete */ + if (deleteSubscriberPostNotify) { + deleteSubscriber(subscriberToNotify); + } +} + +void AgpsStateMachine::transitionState(AgpsState newState){ + + LOC_LOGD("transitionState(): SM %p, old %d, new %d", + this, mState, newState); + + mState = newState; + + // notify state transitions to all subscribers ? +} + +void AgpsStateMachine::addSubscriber(AgpsSubscriber* subscriberToAdd){ + + LOC_LOGD("addSubscriber(): SM %p, Subscriber %p", + this, subscriberToAdd); + + // Check if subscriber is already present in the current list + // If not, then add + std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); + for(; it != mSubscriberList.end(); it++){ + AgpsSubscriber* subscriber = *it; + if(subscriber->equals(subscriberToAdd)){ + LOC_LOGE("Subscriber already in list"); + return; + } + } + + AgpsSubscriber* cloned = subscriberToAdd->clone(); + LOC_LOGD("addSubscriber(): cloned subscriber: %p", cloned); + mSubscriberList.push_back(cloned); +} + +void AgpsStateMachine::deleteSubscriber(AgpsSubscriber* subscriberToDelete){ + + LOC_LOGD("deleteSubscriber(): SM %p, Subscriber %p", + this, subscriberToDelete); + + std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); + while ( it != mSubscriberList.end() ) { + + AgpsSubscriber* subscriber = *it; + if(subscriber && subscriber->equals(subscriberToDelete)){ + + it = mSubscriberList.erase(it); + delete subscriber; + }else{ + it++; + } + } +} + +bool AgpsStateMachine::anyActiveSubscribers(){ + + std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); + for(; it != mSubscriberList.end(); it++){ + AgpsSubscriber* subscriber = *it; + if(!subscriber->mIsInactive){ + return true; + } + } + return false; +} + +void AgpsStateMachine::setAPN(char* apn, unsigned int len){ + + if (NULL != mAPN) { + delete mAPN; + } + + if(apn == NULL || len <= 0){ + LOC_LOGD("Invalid apn len (%d) or null apn", len); + mAPN = NULL; + mAPNLen = 0; + } + + if (NULL != apn) { + mAPN = new char[len+1]; + memcpy(mAPN, apn, len); + mAPN[len] = '\0'; + mAPNLen = len; + } +} + +AgpsSubscriber* AgpsStateMachine::getSubscriber(int connHandle){ + + /* Go over the subscriber list */ + std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); + for(; it != mSubscriberList.end(); it++){ + AgpsSubscriber* subscriber = *it; + if(subscriber->mConnHandle == connHandle){ + return subscriber; + } + } + + /* Not found, return NULL */ + return NULL; +} + +AgpsSubscriber* AgpsStateMachine::getFirstSubscriber(bool isInactive){ + + /* Go over the subscriber list */ + std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); + for(; it != mSubscriberList.end(); it++){ + AgpsSubscriber* subscriber = *it; + if(subscriber->mIsInactive == isInactive){ + return subscriber; + } + } + + /* Not found, return NULL */ + return NULL; +} + +void AgpsStateMachine::dropAllSubscribers(){ + + LOC_LOGD("dropAllSubscribers(): SM %p", this); + + /* Go over the subscriber list */ + std::list<AgpsSubscriber*>::const_iterator it = mSubscriberList.begin(); + while ( it != mSubscriberList.end() ){ + AgpsSubscriber* subscriber = *it; + it = mSubscriberList.erase(it); + delete subscriber; + } +} + +/* -------------------------------------------------------------------- + * DS State Machine Methods + * -------------------------------------------------------------------*/ +const int DSStateMachine::MAX_START_DATA_CALL_RETRIES = 4; +const int DSStateMachine::DATA_CALL_RETRY_DELAY_MSEC = 500; + +/* Overridden method + * DS SM needs to handle one scenario differently */ +void DSStateMachine::processAgpsEvent(AgpsEvent event){ + + LOC_LOGD("DSStateMachine::processAgpsEvent() %d", event); + + /* DS Client call setup APIs don't return failure/closure separately. + * Hence we receive RELEASED event in both cases. + * If we are in pending, we should consider RELEASED as DENIED */ + if(event == AGPS_EVENT_RELEASED && mState == AGPS_STATE_PENDING){ + + LOC_LOGD("Translating RELEASED to DENIED event"); + event = AGPS_EVENT_DENIED; + } + + /* Redirect process to base class */ + AgpsStateMachine::processAgpsEvent(event); +} + +/* Timer Callback + * For the retry timer started in case of DS Client call setup failure */ +void delay_callback(void *callbackData, int result) +{ + LOC_LOGD("delay_callback(): cbData %p", callbackData); + + (void)result; + + if(callbackData == NULL) { + LOC_LOGE("delay_callback(): NULL argument received !"); + return; + } + DSStateMachine* dsStateMachine = (DSStateMachine *)callbackData; + dsStateMachine->retryCallback(); +} + +/* Invoked from Timer Callback + * For the retry timer started in case of DS Client call setup failure */ +void DSStateMachine :: retryCallback() +{ + LOC_LOGD("DSStateMachine::retryCallback()"); + + /* Request SUPL ES + * There must be at least one active subscriber in list */ + AgpsSubscriber* subscriber = getFirstSubscriber(false); + if(subscriber == NULL) { + + LOC_LOGE("No active subscriber for DS Client call setup"); + return; + } + + /* Send message to retry */ + mAgpsManager->mSendMsgToAdapterQueueFn( + new AgpsMsgRequestATL( + mAgpsManager, subscriber->mConnHandle, + LOC_AGPS_TYPE_SUPL_ES)); +} + +/* Overridden method + * Request or Release data connection + * bool request : + * true = Request data connection + * false = Release data connection */ +int DSStateMachine::requestOrReleaseDataConn(bool request){ + + LOC_LOGD("DSStateMachine::requestOrReleaseDataConn(): " + "request %d", request); + + /* Release data connection required ? */ + if(!request && mAgpsManager->mDSClientStopDataCallFn){ + + mAgpsManager->mDSClientStopDataCallFn(); + LOC_LOGD("DS Client release data call request sent !"); + return 0; + } + + /* Setup data connection request + * There must be at least one active subscriber in list */ + AgpsSubscriber* subscriber = getFirstSubscriber(false); + if(subscriber == NULL) { + + LOC_LOGE("No active subscriber for DS Client call setup"); + return -1; + } + + /* DS Client Fn registered ? */ + if(!mAgpsManager->mDSClientOpenAndStartDataCallFn){ + + LOC_LOGE("DS Client start fn not registered, fallback to SUPL ATL"); + notifyEventToSubscriber(AGPS_EVENT_DENIED, subscriber, false); + return -1; + } + + /* Setup the call */ + int ret = mAgpsManager->mDSClientOpenAndStartDataCallFn(); + + /* Check if data call start failed */ + switch (ret) { + + case LOC_API_ADAPTER_ERR_ENGINE_BUSY: + LOC_LOGE("DS Client open call failed, err: %d", ret); + mRetries++; + if(mRetries > MAX_START_DATA_CALL_RETRIES) { + + LOC_LOGE("DS Client call retries exhausted, " + "falling back to normal SUPL ATL"); + notifyEventToSubscriber(AGPS_EVENT_DENIED, subscriber, false); + } + /* Retry DS Client call setup after some delay */ + else if(loc_timer_start( + DATA_CALL_RETRY_DELAY_MSEC, delay_callback, this)) { + LOC_LOGE("Error: Could not start delay thread\n"); + return -1; + } + break; + + case LOC_API_ADAPTER_ERR_UNSUPPORTED: + LOC_LOGE("No emergency profile found. Fall back to normal SUPL ATL"); + notifyEventToSubscriber(AGPS_EVENT_DENIED, subscriber, false); + break; + + case LOC_API_ADAPTER_ERR_SUCCESS: + LOC_LOGD("Request to start data call sent"); + break; + + default: + LOC_LOGE("Unrecognized return value: %d", ret); + } + + return ret; +} + +void DSStateMachine::notifyEventToSubscriber( + AgpsEvent event, AgpsSubscriber* subscriberToNotify, + bool deleteSubscriberPostNotify) { + + LOC_LOGD("DSStateMachine::notifyEventToSubscriber"); + + switch (event){ + + case AGPS_EVENT_GRANTED: + mAgpsManager->mAtlOpenStatusCb( + subscriberToNotify->mConnHandle, 1, NULL, + AGPS_APN_BEARER_INVALID, LOC_AGPS_TYPE_SUPL_ES); + break; + + case AGPS_EVENT_DENIED: + /* Now try with regular SUPL + * We need to send request via message queue */ + mRetries = 0; + mAgpsManager->mSendMsgToAdapterQueueFn( + new AgpsMsgRequestATL( + mAgpsManager, subscriberToNotify->mConnHandle, + LOC_AGPS_TYPE_SUPL)); + break; + + case AGPS_EVENT_UNSUBSCRIBE: + mAgpsManager->mAtlCloseStatusCb(subscriberToNotify->mConnHandle, 1); + break; + + case AGPS_EVENT_RELEASED: + mAgpsManager->mDSClientCloseDataCallFn(); + break; + + default: + LOC_LOGE("Invalid event %d", event); + } + + /* Search this subscriber in list and delete */ + if (deleteSubscriberPostNotify) { + deleteSubscriber(subscriberToNotify); + } +} + +/* -------------------------------------------------------------------- + * Loc AGPS Manager Methods + * -------------------------------------------------------------------*/ + +/* CREATE AGPS STATE MACHINES + * Must be invoked in Msg Handler context */ +void AgpsManager::createAgpsStateMachines() { + + LOC_LOGD("AgpsManager::createAgpsStateMachines"); + + bool agpsCapable = + ((loc_core::ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSA) || + (loc_core::ContextBase::mGps_conf.CAPABILITIES & LOC_GPS_CAPABILITY_MSB)); + + if (NULL == mInternetNif) { + mInternetNif = new AgpsStateMachine(this, LOC_AGPS_TYPE_WWAN_ANY); + LOC_LOGD("Internet NIF: %p", mInternetNif); + } + if (agpsCapable) { + if (NULL == mAgnssNif) { + mAgnssNif = new AgpsStateMachine(this, LOC_AGPS_TYPE_SUPL); + LOC_LOGD("AGNSS NIF: %p", mAgnssNif); + } + if (NULL == mDsNif && + loc_core::ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL){ + + if(!mDSClientInitFn){ + + LOC_LOGE("DS Client Init Fn not registered !"); + return; + } + if(mDSClientInitFn(false) != 0){ + + LOC_LOGE("Failed to init data service client"); + return; + } + mDsNif = new DSStateMachine(this); + LOC_LOGD("DS NIF: %p", mDsNif); + } + } +} + +AgpsStateMachine* AgpsManager::getAgpsStateMachine(AGpsExtType agpsType) { + + LOC_LOGD("AgpsManager::getAgpsStateMachine(): agpsType %d", agpsType); + + switch (agpsType) { + + case LOC_AGPS_TYPE_INVALID: + case LOC_AGPS_TYPE_SUPL: + if(mAgnssNif == NULL){ + LOC_LOGE("NULL AGNSS NIF !"); + } + return mAgnssNif; + + case LOC_AGPS_TYPE_SUPL_ES: + if (loc_core::ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL) { + if (mDsNif == NULL) { + createAgpsStateMachines(); + } + return mDsNif; + } else { + return mAgnssNif; + } + + default: + return mInternetNif; + } + + LOC_LOGE("No SM found !"); + return NULL; +} + +void AgpsManager::requestATL(int connHandle, AGpsExtType agpsType){ + + LOC_LOGD("AgpsManager::requestATL(): connHandle %d, agpsType %d", + connHandle, agpsType); + + AgpsStateMachine* sm = getAgpsStateMachine(agpsType); + + if(sm == NULL){ + + LOC_LOGE("No AGPS State Machine for agpsType: %d", agpsType); + mAtlOpenStatusCb( + connHandle, 0, NULL, AGPS_APN_BEARER_INVALID, agpsType); + return; + } + + /* Invoke AGPS SM processing */ + AgpsSubscriber subscriber(connHandle); + sm->setCurrentSubscriber(&subscriber); + + /* If DS State Machine, wait for close complete */ + if(agpsType == LOC_AGPS_TYPE_SUPL_ES){ + subscriber.mWaitForCloseComplete = true; + } + + /* Send subscriber event */ + sm->processAgpsEvent(AGPS_EVENT_SUBSCRIBE); +} + +void AgpsManager::releaseATL(int connHandle){ + + LOC_LOGD("AgpsManager::releaseATL(): connHandle %d", connHandle); + + /* First find the subscriber with specified handle. + * We need to search in all state machines. */ + AgpsStateMachine* sm = NULL; + AgpsSubscriber* subscriber = NULL; + + if (mAgnssNif && + (subscriber = mAgnssNif->getSubscriber(connHandle)) != NULL) { + sm = mAgnssNif; + } + else if (mInternetNif && + (subscriber = mInternetNif->getSubscriber(connHandle)) != NULL) { + sm = mInternetNif; + } + else if (mDsNif && + (subscriber = mDsNif->getSubscriber(connHandle)) != NULL) { + sm = mDsNif; + } + + if(sm == NULL){ + LOC_LOGE("Subscriber with connHandle %d not found in any SM", + connHandle); + mAtlCloseStatusCb(connHandle, 0); + return; + } + + /* Now send unsubscribe event */ + sm->setCurrentSubscriber(subscriber); + sm->processAgpsEvent(AGPS_EVENT_UNSUBSCRIBE); +} + +void AgpsManager::reportDataCallOpened(){ + + LOC_LOGD("AgpsManager::reportDataCallOpened"); + + if (mDsNif) { + mDsNif->processAgpsEvent(AGPS_EVENT_GRANTED); + } +} + +void AgpsManager::reportDataCallClosed(){ + + LOC_LOGD("AgpsManager::reportDataCallClosed"); + + if (mDsNif) { + mDsNif->processAgpsEvent(AGPS_EVENT_RELEASED); + } +} + +void AgpsManager::reportAtlOpenSuccess( + AGpsExtType agpsType, char* apnName, int apnLen, + LocApnIpType ipType){ + + LOC_LOGD("AgpsManager::reportAtlOpenSuccess(): " + "AgpsType %d, APN [%s], Len %d, IPType %d", + agpsType, apnName, apnLen, ipType); + + /* Find the state machine instance */ + AgpsStateMachine* sm = getAgpsStateMachine(agpsType); + + /* Convert LocApnIpType sent by framework to AGpsBearerType */ + AGpsBearerType bearerType; + switch (ipType) { + case LOC_APN_IP_IPV4: + bearerType = AGPS_APN_BEARER_IPV4; + break; + case LOC_APN_IP_IPV6: + bearerType = AGPS_APN_BEARER_IPV6; + break; + case LOC_APN_IP_IPV4V6: + bearerType = AGPS_APN_BEARER_IPV4V6; + break; + default: + bearerType = AGPS_APN_BEARER_IPV4; + break; + } + + /* Set bearer and apn info in state machine instance */ + sm->setBearer(bearerType); + sm->setAPN(apnName, apnLen); + + /* Send GRANTED event to state machine */ + sm->processAgpsEvent(AGPS_EVENT_GRANTED); +} + +void AgpsManager::reportAtlOpenFailed(AGpsExtType agpsType){ + + LOC_LOGD("AgpsManager::reportAtlOpenFailed(): AgpsType %d", agpsType); + + /* Fetch SM and send DENIED event */ + AgpsStateMachine* sm = getAgpsStateMachine(agpsType); + sm->processAgpsEvent(AGPS_EVENT_DENIED); +} + +void AgpsManager::reportAtlClosed(AGpsExtType agpsType){ + + LOC_LOGD("AgpsManager::reportAtlClosed(): AgpsType %d", agpsType); + + /* Fetch SM and send RELEASED event */ + AgpsStateMachine* sm = getAgpsStateMachine(agpsType); + sm->processAgpsEvent(AGPS_EVENT_RELEASED); +} + +void AgpsManager::handleModemSSR(){ + + LOC_LOGD("AgpsManager::handleModemSSR"); + + /* Drop subscribers from all state machines */ + if (mAgnssNif){ + mAgnssNif->dropAllSubscribers(); + } + if (mInternetNif){ + mInternetNif->dropAllSubscribers(); + } + if(mDsNif){ + mDsNif->dropAllSubscribers(); + } + + // reinitialize DS client in SSR mode + if(loc_core::ContextBase::mGps_conf. + USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL){ + + mDSClientStopDataCallFn(); + mDSClientCloseDataCallFn(); + mDSClientReleaseFn(); + + mDSClientInitFn(true); + } +} + +AGpsBearerType AgpsUtils::ipTypeToBearerType(LocApnIpType ipType) { + + switch (ipType) { + + case LOC_APN_IP_IPV4: + return AGPS_APN_BEARER_IPV4; + + case LOC_APN_IP_IPV6: + return AGPS_APN_BEARER_IPV6; + + case LOC_APN_IP_IPV4V6: + return AGPS_APN_BEARER_IPV4V6; + + default: + return AGPS_APN_BEARER_IPV4; + } +} + +LocApnIpType AgpsUtils::bearerTypeToIpType(AGpsBearerType bearerType){ + + switch (bearerType) { + + case AGPS_APN_BEARER_IPV4: + return LOC_APN_IP_IPV4; + + case AGPS_APN_BEARER_IPV6: + return LOC_APN_IP_IPV6; + + case AGPS_APN_BEARER_IPV4V6: + return LOC_APN_IP_IPV4V6; + + default: + return LOC_APN_IP_IPV4; + } +} diff --git a/gnss/Agps.h b/gnss/Agps.h new file mode 100644 index 0000000..1e95a42 --- /dev/null +++ b/gnss/Agps.h @@ -0,0 +1,446 @@ +/* Copyright (c) 2012-2017, The Linux Foundation. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of The Linux Foundation, nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE + * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN + * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + */ + +#ifndef AGPS_H +#define AGPS_H + +#include <functional> +#include <list> +#include <MsgTask.h> +#include <gps_extended_c.h> +#include <platform_lib_log_util.h> + +/* ATL callback function pointers + * Passed in by Adapter to AgpsManager */ +typedef std::function<void( + int handle, int isSuccess, char* apn, + AGpsBearerType bearerType, AGpsExtType agpsType)> AgpsAtlOpenStatusCb; + +typedef std::function<void(int handle, int isSuccess)> AgpsAtlCloseStatusCb; + +/* DS Client control APIs + * Passed in by Adapter to AgpsManager */ +typedef std::function<int(bool isDueToSSR)> AgpsDSClientInitFn; +typedef std::function<int()> AgpsDSClientOpenAndStartDataCallFn; +typedef std::function<void()> AgpsDSClientStopDataCallFn; +typedef std::function<void()> AgpsDSClientCloseDataCallFn; +typedef std::function<void()> AgpsDSClientReleaseFn; + +/* Post message to adapter's message queue */ +typedef std::function<void(LocMsg* msg)> SendMsgToAdapterMsgQueueFn; + +/* AGPS States */ +typedef enum { + AGPS_STATE_INVALID = 0, + AGPS_STATE_RELEASED, + AGPS_STATE_PENDING, + AGPS_STATE_ACQUIRED, + AGPS_STATE_RELEASING +} AgpsState; + +typedef enum { + AGPS_EVENT_INVALID = 0, + AGPS_EVENT_SUBSCRIBE, + AGPS_EVENT_UNSUBSCRIBE, + AGPS_EVENT_GRANTED, + AGPS_EVENT_RELEASED, + AGPS_EVENT_DENIED +} AgpsEvent; + +/* Notification Types sent to subscribers */ +typedef enum { + AGPS_NOTIFICATION_TYPE_INVALID = 0, + + /* Meant for all subscribers, either active or inactive */ + AGPS_NOTIFICATION_TYPE_FOR_ALL_SUBSCRIBERS, + + /* Meant for only inactive subscribers */ + AGPS_NOTIFICATION_TYPE_FOR_INACTIVE_SUBSCRIBERS, + + /* Meant for only active subscribers */ + AGPS_NOTIFICATION_TYPE_FOR_ACTIVE_SUBSCRIBERS +} AgpsNotificationType; + +/* Framework AGNSS interface + * This interface is defined in IAGnssCallback provided by + * Android Framework. + * Must be kept in sync with that interface. */ +namespace AgpsFrameworkInterface { + + /** AGNSS type **/ + enum AGnssType : uint8_t { + TYPE_SUPL = 1, + TYPE_C2K = 2 + }; + + enum AGnssStatusValue : uint8_t { + /** GNSS requests data connection for AGNSS. */ + REQUEST_AGNSS_DATA_CONN = 1, + /** GNSS releases the AGNSS data connection. */ + RELEASE_AGNSS_DATA_CONN = 2, + /** AGNSS data connection initiated */ + AGNSS_DATA_CONNECTED = 3, + /** AGNSS data connection completed */ + AGNSS_DATA_CONN_DONE = 4, + /** AGNSS data connection failed */ + AGNSS_DATA_CONN_FAILED = 5 + }; + + /* + * Represents the status of AGNSS augmented to support IPv4. + */ + struct AGnssStatusIpV4 { + AGnssType type; + AGnssStatusValue status; + /* + * 32-bit IPv4 address. + */ + unsigned int ipV4Addr; + }; + + /* + * Represents the status of AGNSS augmented to support IPv6. + */ + struct AGnssStatusIpV6 { + AGnssType type; + AGnssStatusValue status; + /* + * 128-bit IPv6 address. + */ + unsigned char ipV6Addr[16]; + }; + + /* + * Callback with AGNSS(IpV4) status information. + * + * @param status Will be of type AGnssStatusIpV4. + */ + typedef void (*AgnssStatusIpV4Cb)(AGnssStatusIpV4 status); + + /* + * Callback with AGNSS(IpV6) status information. + * + * @param status Will be of type AGnssStatusIpV6. + */ + typedef void (*AgnssStatusIpV6Cb)(AGnssStatusIpV6 status); +} + +/* Classes in this header */ +class AgpsSubscriber; +class AgpsManager; +class AgpsStateMachine; +class DSStateMachine; + + +/* SUBSCRIBER + * Each Subscriber instance corresponds to one AGPS request, + * received by the AGPS state machine */ +class AgpsSubscriber { + +public: + int mConnHandle; + + /* Does this subscriber wait for data call close complete, + * before being notified ATL close ? + * While waiting for data call close, subscriber will be in + * inactive state. */ + bool mWaitForCloseComplete; + bool mIsInactive; + + inline AgpsSubscriber(int connHandle) : + mConnHandle(connHandle), mWaitForCloseComplete(false), + mIsInactive(false) {} + inline virtual ~AgpsSubscriber() {} + + inline virtual bool equals(const AgpsSubscriber *s) const + { return (mConnHandle == s->mConnHandle); } + + inline virtual AgpsSubscriber* clone() + { return new AgpsSubscriber(mConnHandle); } +}; + +/* AGPS STATE MACHINE */ +class AgpsStateMachine { +protected: + /* AGPS Manager instance, from where this state machine is created */ + AgpsManager* mAgpsManager; + + /* List of all subscribers for this State Machine. + * Once a subscriber is notified for ATL open/close status, + * it is deleted */ + std::list<AgpsSubscriber*> mSubscriberList; + + /* Current subscriber, whose request this State Machine is + * currently processing */ + AgpsSubscriber* mCurrentSubscriber; + + /* Current state for this state machine */ + AgpsState mState; + +private: + /* AGPS Type for this state machine + LOC_AGPS_TYPE_ANY 0 + LOC_AGPS_TYPE_SUPL 1 + LOC_AGPS_TYPE_WWAN_ANY 3 + LOC_AGPS_TYPE_SUPL_ES 5 */ + AGpsExtType mAgpsType; + + /* APN and IP Type info for AGPS Call */ + char* mAPN; + unsigned int mAPNLen; + AGpsBearerType mBearer; + +public: + /* CONSTRUCTOR */ + AgpsStateMachine(AgpsManager* agpsManager, AGpsExtType agpsType): + mAgpsManager(agpsManager), mSubscriberList(), + mCurrentSubscriber(NULL), mState(AGPS_STATE_RELEASED), + mAgpsType(agpsType), mAPN(NULL), mAPNLen(0), + mBearer(AGPS_APN_BEARER_INVALID) {}; + + virtual ~AgpsStateMachine() { if(NULL != mAPN) delete[] mAPN; }; + + /* Getter/Setter methods */ + void setAPN(char* apn, unsigned int len); + inline char* getAPN() const { return (char*)mAPN; } + inline void setBearer(AGpsBearerType bearer) { mBearer = bearer; } + inline AGpsBearerType getBearer() const { return mBearer; } + inline AGpsExtType getType() const { return mAgpsType; } + inline void setCurrentSubscriber(AgpsSubscriber* subscriber) + { mCurrentSubscriber = subscriber; } + + /* Fetch subscriber with specified handle */ + AgpsSubscriber* getSubscriber(int connHandle); + + /* Fetch first active or inactive subscriber in list + * isInactive = true : fetch first inactive subscriber + * isInactive = false : fetch first active subscriber */ + AgpsSubscriber* getFirstSubscriber(bool isInactive); + + /* Process LOC AGPS Event being passed in + * onRsrcEvent */ + virtual void processAgpsEvent(AgpsEvent event); + + /* Drop all subscribers, in case of Modem SSR */ + void dropAllSubscribers(); + +protected: + /* Remove the specified subscriber from list if present. + * Also delete the subscriber instance. */ + void deleteSubscriber(AgpsSubscriber* subscriber); + +private: + /* Send call setup request to framework + * sendRsrcRequest(LOC_GPS_REQUEST_AGPS_DATA_CONN) + * sendRsrcRequest(LOC_GPS_RELEASE_AGPS_DATA_CONN) */ + virtual int requestOrReleaseDataConn(bool request); + + /* Individual event processing methods */ + void processAgpsEventSubscribe(); + void processAgpsEventUnsubscribe(); + void processAgpsEventGranted(); + void processAgpsEventReleased(); + void processAgpsEventDenied(); + + /* Clone the passed in subscriber and add to the subscriber list + * if not already present */ + void addSubscriber(AgpsSubscriber* subscriber); + + /* Notify subscribers about AGPS events */ + void notifyAllSubscribers( + AgpsEvent event, bool deleteSubscriberPostNotify, + AgpsNotificationType notificationType); + virtual void notifyEventToSubscriber( + AgpsEvent event, AgpsSubscriber* subscriber, + bool deleteSubscriberPostNotify); + + /* Do we have any subscribers in active state */ + bool anyActiveSubscribers(); + + /* Transition state */ + void transitionState(AgpsState newState); +}; + +/* DS STATE MACHINE */ +class DSStateMachine : public AgpsStateMachine { + +private: + static const int MAX_START_DATA_CALL_RETRIES; + static const int DATA_CALL_RETRY_DELAY_MSEC; + + int mRetries; + +public: + /* CONSTRUCTOR */ + DSStateMachine(AgpsManager* agpsManager): + AgpsStateMachine(agpsManager, LOC_AGPS_TYPE_SUPL_ES), mRetries(0) {} + + /* Overridden method + * DS SM needs to handle one event differently */ + void processAgpsEvent(AgpsEvent event); + + /* Retry callback, used in case call failure */ + void retryCallback(); + +private: + /* Overridden method, different functionality for DS SM + * Send call setup request to framework + * sendRsrcRequest(LOC_GPS_REQUEST_AGPS_DATA_CONN) + * sendRsrcRequest(LOC_GPS_RELEASE_AGPS_DATA_CONN) */ + int requestOrReleaseDataConn(bool request); + + /* Overridden method, different functionality for DS SM */ + void notifyEventToSubscriber( + AgpsEvent event, AgpsSubscriber* subscriber, + bool deleteSubscriberPostNotify); +}; + +/* LOC AGPS MANAGER */ +class AgpsManager { + + friend class AgpsStateMachine; + friend class DSStateMachine; + +public: + /* CONSTRUCTOR */ + AgpsManager(): + mFrameworkStatusV4Cb(NULL), + mAtlOpenStatusCb(), mAtlCloseStatusCb(), + mDSClientInitFn(), mDSClientOpenAndStartDataCallFn(), + mDSClientStopDataCallFn(), mDSClientCloseDataCallFn(), mDSClientReleaseFn(), + mSendMsgToAdapterQueueFn(), + mAgnssNif(NULL), mInternetNif(NULL), mDsNif(NULL) {} + + /* Register callbacks */ + void registerCallbacks( + AgpsFrameworkInterface::AgnssStatusIpV4Cb + frameworkStatusV4Cb, + + AgpsAtlOpenStatusCb atlOpenStatusCb, + AgpsAtlCloseStatusCb atlCloseStatusCb, + + AgpsDSClientInitFn dsClientInitFn, + AgpsDSClientOpenAndStartDataCallFn dsClientOpenAndStartDataCallFn, + AgpsDSClientStopDataCallFn dsClientStopDataCallFn, + AgpsDSClientCloseDataCallFn dsClientCloseDataCallFn, + AgpsDSClientReleaseFn dsClientReleaseFn, + + SendMsgToAdapterMsgQueueFn sendMsgToAdapterQueueFn ){ + + mFrameworkStatusV4Cb = frameworkStatusV4Cb; + + mAtlOpenStatusCb = atlOpenStatusCb; + mAtlCloseStatusCb = atlCloseStatusCb; + + mDSClientInitFn = dsClientInitFn; + mDSClientOpenAndStartDataCallFn = dsClientOpenAndStartDataCallFn; + mDSClientStopDataCallFn = dsClientStopDataCallFn; + mDSClientCloseDataCallFn = dsClientCloseDataCallFn; + mDSClientReleaseFn = dsClientReleaseFn; + + mSendMsgToAdapterQueueFn = sendMsgToAdapterQueueFn; + } + + /* Create all AGPS state machines */ + void createAgpsStateMachines(); + + /* Process incoming ATL requests */ + void requestATL(int connHandle, AGpsExtType agpsType); + void releaseATL(int connHandle); + + /* Process incoming DS Client data call events */ + void reportDataCallOpened(); + void reportDataCallClosed(); + + /* Process incoming framework data call events */ + void reportAtlOpenSuccess( + AGpsExtType agpsType, char* apnName, int apnLen, + LocApnIpType ipType); + void reportAtlOpenFailed(AGpsExtType agpsType); + void reportAtlClosed(AGpsExtType agpsType); + + /* Handle Modem SSR */ + void handleModemSSR(); + +protected: + AgpsFrameworkInterface::AgnssStatusIpV4Cb mFrameworkStatusV4Cb; + + AgpsAtlOpenStatusCb mAtlOpenStatusCb; + AgpsAtlCloseStatusCb mAtlCloseStatusCb; + + AgpsDSClientInitFn mDSClientInitFn; + AgpsDSClientOpenAndStartDataCallFn mDSClientOpenAndStartDataCallFn; + AgpsDSClientStopDataCallFn mDSClientStopDataCallFn; + AgpsDSClientCloseDataCallFn mDSClientCloseDataCallFn; + AgpsDSClientReleaseFn mDSClientReleaseFn; + + SendMsgToAdapterMsgQueueFn mSendMsgToAdapterQueueFn; + + AgpsStateMachine* mAgnssNif; + AgpsStateMachine* mInternetNif; + AgpsStateMachine* mDsNif; + +private: + /* Fetch state machine for handling request ATL call */ + AgpsStateMachine* getAgpsStateMachine(AGpsExtType agpsType); +}; + +/* Request SUPL/INTERNET/SUPL_ES ATL + * This LocMsg is defined in this header since it has to be used from more + * than one place, other Agps LocMsg are restricted to GnssAdapter and + * declared inline */ +struct AgpsMsgRequestATL: public LocMsg { + + AgpsManager* mAgpsManager; + int mConnHandle; + AGpsExtType mAgpsType; + + inline AgpsMsgRequestATL(AgpsManager* agpsManager, int connHandle, + AGpsExtType agpsType) : + LocMsg(), mAgpsManager(agpsManager), mConnHandle(connHandle), mAgpsType( + agpsType) { + + LOC_LOGV("AgpsMsgRequestATL"); + } + + inline virtual void proc() const { + + LOC_LOGV("AgpsMsgRequestATL::proc()"); + mAgpsManager->requestATL(mConnHandle, mAgpsType); + } +}; + +namespace AgpsUtils { + +AGpsBearerType ipTypeToBearerType(LocApnIpType ipType); +LocApnIpType bearerTypeToIpType(AGpsBearerType bearerType); + +} + +#endif /* AGPS_H */ diff --git a/gnss/Android.mk b/gnss/Android.mk index 16d796c..1f0a549 100644 --- a/gnss/Android.mk +++ b/gnss/Android.mk @@ -20,7 +20,8 @@ LOCAL_SHARED_LIBRARIES := \ LOCAL_SRC_FILES += \ location_gnss.cpp \ - GnssAdapter.cpp + GnssAdapter.cpp \ + Agps.cpp LOCAL_CFLAGS += \ -fno-short-enums \ diff --git a/gnss/GnssAdapter.cpp b/gnss/GnssAdapter.cpp index 1ddb41d..3a6ae55 100644 --- a/gnss/GnssAdapter.cpp +++ b/gnss/GnssAdapter.cpp @@ -39,6 +39,7 @@ #include <GnssAdapter.h> #include <string> #include <loc_log.h> +#include <Agps.h> using namespace loc_core; @@ -55,7 +56,8 @@ GnssAdapter::GnssAdapter() : mGnssSvIdUsedInPosAvail(false), mControlCallbacks(), mPowerVoteId(0), - mNiData() + mNiData(), + mAgpsManager() { LOC_LOGD("%s]: Constructor %p", __func__, this); mUlpPositionMode.mode = LOC_POSITION_MODE_INVALID; @@ -2878,3 +2880,334 @@ GnssAdapter::generateNmeaGGA(const UlpLocation& ulpLocation, length = nmeaPutChecksum(sentence, size); reportNmeaEvent(sentence, length); } + +/* INIT LOC AGPS MANAGER */ +void GnssAdapter::initAgpsCommand(void* statusV4Cb){ + + LOC_LOGI("GnssAdapter::initAgpsCommand"); + + /* Set ATL open/close callbacks */ + AgpsAtlOpenStatusCb atlOpenStatusCb = + [this](int handle, int isSuccess, char* apn, + AGpsBearerType bearerType, AGpsExtType agpsType) { + + mLocApi->atlOpenStatus( + handle, isSuccess, apn, bearerType, agpsType); + }; + AgpsAtlCloseStatusCb atlCloseStatusCb = + [this](int handle, int isSuccess) { + + mLocApi->atlCloseStatus(handle, isSuccess); + }; + + /* Register DS Client APIs */ + AgpsDSClientInitFn dsClientInitFn = + [this](bool isDueToSSR) { + + return mLocApi->initDataServiceClient(isDueToSSR); + }; + + AgpsDSClientOpenAndStartDataCallFn dsClientOpenAndStartDataCallFn = + [this] { + + return mLocApi->openAndStartDataCall(); + }; + + AgpsDSClientStopDataCallFn dsClientStopDataCallFn = + [this] { + + mLocApi->stopDataCall(); + }; + + AgpsDSClientCloseDataCallFn dsClientCloseDataCallFn = + [this] { + + mLocApi->closeDataCall(); + }; + + AgpsDSClientReleaseFn dsClientReleaseFn = + [this] { + + mLocApi->releaseDataServiceClient(); + }; + + /* Send Msg function */ + SendMsgToAdapterMsgQueueFn sendMsgFn = + [this](LocMsg* msg) { + + sendMsg(msg); + }; + + /* Message to initialize AGPS module */ + struct AgpsMsgInit: public LocMsg { + + AgpsManager* mAgpsManager; + + AgpsFrameworkInterface::AgnssStatusIpV4Cb mFrameworkStatusV4Cb; + + AgpsAtlOpenStatusCb mAtlOpenStatusCb; + AgpsAtlCloseStatusCb mAtlCloseStatusCb; + + AgpsDSClientInitFn mDSClientInitFn; + AgpsDSClientOpenAndStartDataCallFn mDSClientOpenAndStartDataCallFn; + AgpsDSClientStopDataCallFn mDSClientStopDataCallFn; + AgpsDSClientCloseDataCallFn mDSClientCloseDataCallFn; + AgpsDSClientReleaseFn mDSClientReleaseFn; + + SendMsgToAdapterMsgQueueFn mSendMsgFn; + + inline AgpsMsgInit(AgpsManager* agpsManager, + AgpsFrameworkInterface::AgnssStatusIpV4Cb frameworkStatusV4Cb, + AgpsAtlOpenStatusCb atlOpenStatusCb, + AgpsAtlCloseStatusCb atlCloseStatusCb, + AgpsDSClientInitFn dsClientInitFn, + AgpsDSClientOpenAndStartDataCallFn dsClientOpenAndStartDataCallFn, + AgpsDSClientStopDataCallFn dsClientStopDataCallFn, + AgpsDSClientCloseDataCallFn dsClientCloseDataCallFn, + AgpsDSClientReleaseFn dsClientReleaseFn, + SendMsgToAdapterMsgQueueFn sendMsgFn) : + LocMsg(), mAgpsManager(agpsManager), mFrameworkStatusV4Cb( + frameworkStatusV4Cb), mAtlOpenStatusCb(atlOpenStatusCb), mAtlCloseStatusCb( + atlCloseStatusCb), mDSClientInitFn(dsClientInitFn), mDSClientOpenAndStartDataCallFn( + dsClientOpenAndStartDataCallFn), mDSClientStopDataCallFn( + dsClientStopDataCallFn), mDSClientCloseDataCallFn( + dsClientCloseDataCallFn), mDSClientReleaseFn( + dsClientReleaseFn), mSendMsgFn(sendMsgFn) { + + LOC_LOGV("AgpsMsgInit"); + } + + inline virtual void proc() const { + + LOC_LOGV("AgpsMsgInit::proc()"); + + mAgpsManager->registerCallbacks(mFrameworkStatusV4Cb, mAtlOpenStatusCb, + mAtlCloseStatusCb, mDSClientInitFn, + mDSClientOpenAndStartDataCallFn, mDSClientStopDataCallFn, + mDSClientCloseDataCallFn, mDSClientReleaseFn, mSendMsgFn); + + mAgpsManager->createAgpsStateMachines(); + } + }; + + /* Send message to initialize AGPS Manager */ + sendMsg(new AgpsMsgInit( + &mAgpsManager, + (AgpsFrameworkInterface::AgnssStatusIpV4Cb)statusV4Cb, + atlOpenStatusCb, atlCloseStatusCb, + dsClientInitFn, dsClientOpenAndStartDataCallFn, + dsClientStopDataCallFn, dsClientCloseDataCallFn, + dsClientReleaseFn, + sendMsgFn)); +} + +/* GnssAdapter::requestATL + * Method triggered in QMI thread as part of handling below message: + * eQMI_LOC_SERVER_REQUEST_OPEN_V02 + * Triggers the AGPS state machine to setup AGPS call for below WWAN types: + * eQMI_LOC_WWAN_TYPE_INTERNET_V02 + * eQMI_LOC_WWAN_TYPE_AGNSS_V02 */ +bool GnssAdapter::requestATL(int connHandle, LocAGpsType agpsType){ + + LOC_LOGI("GnssAdapter::requestATL"); + + sendMsg( new AgpsMsgRequestATL( + &mAgpsManager, connHandle, (AGpsExtType)agpsType)); + + return true; +} + +/* GnssAdapter::requestSuplES + * Method triggered in QMI thread as part of handling below message: + * eQMI_LOC_SERVER_REQUEST_OPEN_V02 + * Triggers the AGPS state machine to setup AGPS call for below WWAN types: + * eQMI_LOC_WWAN_TYPE_AGNSS_EMERGENCY_V02 */ +bool GnssAdapter::requestSuplES(int connHandle){ + + LOC_LOGI("GnssAdapter::requestSuplES"); + + sendMsg( new AgpsMsgRequestATL( + &mAgpsManager, connHandle, LOC_AGPS_TYPE_SUPL_ES)); + + return true; +} + +/* GnssAdapter::releaseATL + * Method triggered in QMI thread as part of handling below message: + * eQMI_LOC_SERVER_REQUEST_CLOSE_V02 + * Triggers teardown of an existing AGPS call */ +bool GnssAdapter::releaseATL(int connHandle){ + + LOC_LOGI("GnssAdapter::releaseATL"); + + /* Release SUPL/INTERNET/SUPL_ES ATL */ + struct AgpsMsgReleaseATL: public LocMsg { + + AgpsManager* mAgpsManager; + int mConnHandle; + + inline AgpsMsgReleaseATL(AgpsManager* agpsManager, int connHandle) : + LocMsg(), mAgpsManager(agpsManager), mConnHandle(connHandle) { + + LOC_LOGV("AgpsMsgReleaseATL"); + } + + inline virtual void proc() const { + + LOC_LOGV("AgpsMsgReleaseATL::proc()"); + mAgpsManager->releaseATL(mConnHandle); + } + }; + + sendMsg( new AgpsMsgReleaseATL(&mAgpsManager, connHandle)); + + return true; +} + +/* GnssAdapter::reportDataCallOpened + * DS Client data call opened successfully. + * Send message to AGPS Manager to handle. */ +bool GnssAdapter::reportDataCallOpened(){ + + LOC_LOGI("GnssAdapter::reportDataCallOpened"); + + struct AgpsMsgSuplEsOpened: public LocMsg { + + AgpsManager* mAgpsManager; + + inline AgpsMsgSuplEsOpened(AgpsManager* agpsManager) : + LocMsg(), mAgpsManager(agpsManager) { + + LOC_LOGV("AgpsMsgSuplEsOpened"); + } + + inline virtual void proc() const { + + LOC_LOGV("AgpsMsgSuplEsOpened::proc()"); + mAgpsManager->reportDataCallOpened(); + } + }; + + sendMsg( new AgpsMsgSuplEsOpened(&mAgpsManager)); + + return true; +} + +/* GnssAdapter::reportDataCallClosed + * DS Client data call closed. + * Send message to AGPS Manager to handle. */ +bool GnssAdapter::reportDataCallClosed(){ + + LOC_LOGI("GnssAdapter::reportDataCallClosed"); + + struct AgpsMsgSuplEsClosed: public LocMsg { + + AgpsManager* mAgpsManager; + + inline AgpsMsgSuplEsClosed(AgpsManager* agpsManager) : + LocMsg(), mAgpsManager(agpsManager) { + + LOC_LOGV("AgpsMsgSuplEsClosed"); + } + + inline virtual void proc() const { + + LOC_LOGV("AgpsMsgSuplEsClosed::proc()"); + mAgpsManager->reportDataCallClosed(); + } + }; + + sendMsg( new AgpsMsgSuplEsClosed(&mAgpsManager)); + + return true; +} + +void GnssAdapter::dataConnOpenCommand( + AGpsExtType agpsType, + const char* apnName, int apnLen, LocApnIpType ipType){ + + LOC_LOGI("GnssAdapter::frameworkDataConnOpen"); + + struct AgpsMsgAtlOpenSuccess: public LocMsg { + + AgpsManager* mAgpsManager; + AGpsExtType mAgpsType; + char* mApnName; + int mApnLen; + LocApnIpType mIpType; + + inline AgpsMsgAtlOpenSuccess(AgpsManager* agpsManager, AGpsExtType agpsType, + const char* apnName, int apnLen, LocApnIpType ipType) : + LocMsg(), mAgpsManager(agpsManager), mAgpsType(agpsType), mApnName( + new char[apnLen + 1]), mApnLen(apnLen), mIpType(ipType) { + + LOC_LOGV("AgpsMsgAtlOpenSuccess"); + memcpy(mApnName, apnName, apnLen); + mApnName[apnLen] = 0; + } + + inline ~AgpsMsgAtlOpenSuccess() { + delete[] mApnName; + } + + inline virtual void proc() const { + + LOC_LOGV("AgpsMsgAtlOpenSuccess::proc()"); + mAgpsManager->reportAtlOpenSuccess(mAgpsType, mApnName, mApnLen, + mIpType); + } + }; + + sendMsg( new AgpsMsgAtlOpenSuccess( + &mAgpsManager, (AGpsExtType)agpsType, apnName, apnLen, ipType)); +} + +void GnssAdapter::dataConnClosedCommand(AGpsExtType agpsType){ + + LOC_LOGI("GnssAdapter::frameworkDataConnClosed"); + + struct AgpsMsgAtlClosed: public LocMsg { + + AgpsManager* mAgpsManager; + AGpsExtType mAgpsType; + + inline AgpsMsgAtlClosed(AgpsManager* agpsManager, AGpsExtType agpsType) : + LocMsg(), mAgpsManager(agpsManager), mAgpsType(agpsType) { + + LOC_LOGV("AgpsMsgAtlClosed"); + } + + inline virtual void proc() const { + + LOC_LOGV("AgpsMsgAtlClosed::proc()"); + mAgpsManager->reportAtlClosed(mAgpsType); + } + }; + + sendMsg( new AgpsMsgAtlClosed(&mAgpsManager, (AGpsExtType)agpsType)); +} + +void GnssAdapter::dataConnFailedCommand(AGpsExtType agpsType){ + + LOC_LOGI("GnssAdapter::frameworkDataConnFailed"); + + struct AgpsMsgAtlOpenFailed: public LocMsg { + + AgpsManager* mAgpsManager; + AGpsExtType mAgpsType; + + inline AgpsMsgAtlOpenFailed(AgpsManager* agpsManager, AGpsExtType agpsType) : + LocMsg(), mAgpsManager(agpsManager), mAgpsType(agpsType) { + + LOC_LOGV("AgpsMsgAtlOpenFailed"); + } + + inline virtual void proc() const { + + LOC_LOGV("AgpsMsgAtlOpenFailed::proc()"); + mAgpsManager->reportAtlOpenFailed(mAgpsType); + } + }; + + sendMsg( new AgpsMsgAtlOpenFailed(&mAgpsManager, (AGpsExtType)agpsType)); +} diff --git a/gnss/GnssAdapter.h b/gnss/GnssAdapter.h index 5bd2a12..f5a5300 100644 --- a/gnss/GnssAdapter.h +++ b/gnss/GnssAdapter.h @@ -33,6 +33,7 @@ #include <LocDualContext.h> #include <UlpProxyBase.h> #include <LocationAPI.h> +#include <Agps.h> #define MAX_URL_LEN 256 #define NMEA_SENTENCE_MAX_LENGTH 200 @@ -95,6 +96,10 @@ class GnssAdapter : public LocAdapterBase { /* ==== NI ============================================================================= */ NiData mNiData; + /* ==== AGPS ========================================================*/ + // This must be initialized via initAgps() + AgpsManager mAgpsManager; + /*==== CONVERSION ===================================================================*/ static void convertOptions(LocPosMode& out, const LocationOptions& options); static void convertLocation(Location& out, const LocGpsLocation& locGpsLocation, @@ -177,6 +182,14 @@ public: void setConfigCommand(); uint32_t* gnssUpdateConfigCommand(GnssConfig config); uint32_t gnssDeleteAidingDataCommand(GnssAidingData& data); + + void initAgpsCommand(void* statusV4Cb); + void dataConnOpenCommand( + AGpsExtType agpsType, + const char* apnName, int apnLen, LocApnIpType ipType); + void dataConnClosedCommand(AGpsExtType agpsType); + void dataConnFailedCommand(AGpsExtType agpsType); + /* ======== RESPONSES ================================================================== */ void reportResponse(LocationError err, uint32_t sessionId); void reportResponse(size_t count, LocationError* errs, uint32_t* ids); @@ -201,6 +214,13 @@ public: virtual void reportGnssMeasurementDataEvent(const GnssMeasurementsNotification& measurementsNotify); virtual void reportSvMeasurementEvent(GnssSvMeasurementSet &svMeasurementSet); virtual void reportSvPolynomialEvent(GnssSvPolynomial &svPolynomial); + + virtual bool requestATL(int connHandle, LocAGpsType agps_type); + virtual bool releaseATL(int connHandle); + virtual bool requestSuplES(int connHandle); + virtual bool reportDataCallOpened(); + virtual bool reportDataCallClosed(); + /* ======== UTILITIES ================================================================= */ void reportPosition(const UlpLocation &ulpLocation, const GpsLocationExtended &locationExtended, diff --git a/gnss/location_gnss.cpp b/gnss/location_gnss.cpp index 242e72e..0995f4b 100644 --- a/gnss/location_gnss.cpp +++ b/gnss/location_gnss.cpp @@ -54,6 +54,11 @@ static uint32_t* gnssUpdateConfig(GnssConfig config); static void injectLocation(double latitude, double longitude, float accuracy); static void injectTime(int64_t time, int64_t timeReference, int32_t uncertainty); +static void agpsInit(void* statusV4Cb); +static void agpsDataConnOpen(AGpsExtType agpsType, const char* apnName, int apnLen, int ipType); +static void agpsDataConnClosed(AGpsExtType agpsType); +static void agpsDataConnFailed(AGpsExtType agpsType); + static const GnssInterface gGnssInterface = { sizeof(GnssInterface), initialize, @@ -71,7 +76,11 @@ static const GnssInterface gGnssInterface = { gnssUpdateConfig, gnssDeleteAidingData, injectLocation, - injectTime + injectTime, + agpsInit, + agpsDataConnOpen, + agpsDataConnClosed, + agpsDataConnFailed }; #ifndef DEBUG_X86 @@ -204,3 +213,29 @@ static void injectTime(int64_t time, int64_t timeReference, int32_t uncertainty) } } +static void agpsInit(void* statusV4Cb) { + + if (NULL != gGnssAdapter) { + gGnssAdapter->initAgpsCommand(statusV4Cb); + } +} +static void agpsDataConnOpen( + AGpsExtType agpsType, const char* apnName, int apnLen, int ipType) { + + if (NULL != gGnssAdapter) { + gGnssAdapter->dataConnOpenCommand( + agpsType, apnName, apnLen, ipType); + } +} +static void agpsDataConnClosed(AGpsExtType agpsType) { + + if (NULL != gGnssAdapter) { + gGnssAdapter->dataConnClosedCommand(agpsType); + } +} +static void agpsDataConnFailed(AGpsExtType agpsType) { + + if (NULL != gGnssAdapter) { + gGnssAdapter->dataConnFailedCommand(agpsType); + } +} diff --git a/location/location_interface.h b/location/location_interface.h index b726931..b084b65 100644 --- a/location/location_interface.h +++ b/location/location_interface.h @@ -49,6 +49,10 @@ struct GnssInterface { uint32_t (*gnssDeleteAidingData)(GnssAidingData& data); void (*injectLocation)(double latitude, double longitude, float accuracy); void (*injectTime)(int64_t time, int64_t timeReference, int32_t uncertainty); + void (*agpsInit)(void* statusV4Cb); + void (*agpsDataConnOpen)(short agpsType, const char* apnName, int apnLen, int ipType); + void (*agpsDataConnClosed)(short agpsType); + void (*agpsDataConnFailed)(short agpsType); }; struct FlpInterface { |