/* 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 #include #include #include /* -------------------------------------------------------------------- * 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: /* Subscriber list should be empty if we are in released state */ if (!mSubscriberList.empty()) { LOC_LOGE("Unexpected event RELEASED in RELEASED state"); } 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::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::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::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::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::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::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::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(): " "SM %p, Event %d Subscriber %p Delete %d", this, event, subscriberToNotify, deleteSubscriberPostNotify); 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(); mAgpsManager->mAtlCloseStatusCb(subscriberToNotify->mConnHandle, 1); 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, false, false); 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; } }