summaryrefslogtreecommitdiff
path: root/gps/gnss/Agps.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'gps/gnss/Agps.cpp')
-rw-r--r--gps/gnss/Agps.cpp912
1 files changed, 912 insertions, 0 deletions
diff --git a/gps/gnss/Agps.cpp b/gps/gnss/Agps.cpp
new file mode 100644
index 0000000..72ce293
--- /dev/null
+++ b/gps/gnss/Agps.cpp
@@ -0,0 +1,912 @@
+/* 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;
+ }
+ 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;
+ }
+ 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){
+
+ AGnssExtStatusIpV4 nifRequest;
+ memset(&nifRequest, 0, sizeof(nifRequest));
+
+ nifRequest.type = mAgpsType;
+
+ if (request) {
+ LOC_LOGD("AGPS Data Conn Request");
+ nifRequest.status = LOC_GPS_REQUEST_AGPS_DATA_CONN;
+ }
+ else{
+ LOC_LOGD("AGPS Data Conn Release");
+ nifRequest.status = 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];
+ if (NULL != mAPN) {
+ 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(): "
+ "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,
+ AGpsBearerType bearerType){
+
+ LOC_LOGD("AgpsManager::reportAtlOpenSuccess(): "
+ "AgpsType %d, APN [%s], Len %d, BearerType %d",
+ agpsType, apnName, apnLen, bearerType);
+
+ /* Find the state machine instance */
+ AgpsStateMachine* sm = getAgpsStateMachine(agpsType);
+
+ /* 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);
+ }
+}