/* Copyright (c) 2011-2013, 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_NDDEBUG 0 #define LOG_TAG "LocSvc_eng" #include #include #include #include #include #include #include //====================================================================== // C callbacks //====================================================================== // This is given to linked_list_add as the dealloc callback // data -- an instance of Subscriber static void deleteObj(void* data) { delete (Subscriber*)data; } // This is given to linked_list_search() as the comparison callback // when the state manchine needs to process for particular subscriber // fromCaller -- caller provides this obj // fromList -- linked_list_search() function take this one from list static bool hasSubscriber(void* fromCaller, void* fromList) { Notification* notification = (Notification*)fromCaller; Subscriber* s1 = (Subscriber*)fromList; return s1->forMe(*notification); } // This is gvien to linked_list_search() to notify subscriber objs // when the state machine needs to inform all subscribers of resource // status changes, e.g. when resource is GRANTED. // fromCaller -- caller provides this ptr to a Notification obj. // fromList -- linked_list_search() function take this one from list static bool notifySubscriber(void* fromCaller, void* fromList) { Notification* notification = (Notification*)fromCaller; Subscriber* s1 = (Subscriber*)fromList; // we notify every subscriber indiscriminatively // each subscriber decides if this notification is interesting. return s1->notifyRsrcStatus(*notification) && // if we do not want to delete the subscriber from the // the list, we must set this to false so this function // returns false notification->postNotifyDelete; } //====================================================================== // Notification //====================================================================== const int Notification::BROADCAST_ALL = 0x80000000; const int Notification::BROADCAST_ACTIVE = 0x80000001; const int Notification::BROADCAST_INACTIVE = 0x80000002; const unsigned char DSStateMachine::MAX_START_DATA_CALL_RETRIES = 4; const unsigned int DSStateMachine::DATA_CALL_RETRY_DELAY_MSEC = 500; //====================================================================== // Subscriber: BITSubscriber / ATLSubscriber / WIFISubscriber //====================================================================== bool Subscriber::forMe(Notification ¬ification) { if (NULL != notification.rcver) { return equals(notification.rcver); } else { return Notification::BROADCAST_ALL == notification.groupID || (Notification::BROADCAST_ACTIVE == notification.groupID && !isInactive()) || (Notification::BROADCAST_INACTIVE == notification.groupID && isInactive()); } } bool BITSubscriber::equals(const Subscriber *s) const { BITSubscriber* bitS = (BITSubscriber*)s; return (ID == bitS->ID && (INADDR_NONE != (unsigned int)ID || 0 == strncmp(mIPv6Addr, bitS->mIPv6Addr, sizeof(mIPv6Addr)))); } bool BITSubscriber::notifyRsrcStatus(Notification ¬ification) { bool notify = forMe(notification); if (notify) { switch(notification.rsrcStatus) { case RSRC_UNSUBSCRIBE: case RSRC_RELEASED: loc_eng_dmn_conn_loc_api_server_data_conn( LOC_ENG_IF_REQUEST_SENDER_ID_GPSONE_DAEMON, GPSONE_LOC_API_IF_RELEASE_SUCCESS); break; case RSRC_DENIED: loc_eng_dmn_conn_loc_api_server_data_conn( LOC_ENG_IF_REQUEST_SENDER_ID_GPSONE_DAEMON, GPSONE_LOC_API_IF_FAILURE); break; case RSRC_GRANTED: loc_eng_dmn_conn_loc_api_server_data_conn( LOC_ENG_IF_REQUEST_SENDER_ID_GPSONE_DAEMON, GPSONE_LOC_API_IF_REQUEST_SUCCESS); break; default: notify = false; } } return notify; } bool ATLSubscriber::notifyRsrcStatus(Notification ¬ification) { bool notify = forMe(notification); if (notify) { switch(notification.rsrcStatus) { case RSRC_UNSUBSCRIBE: case RSRC_RELEASED: ((LocEngAdapter*)mLocAdapter)->atlCloseStatus(ID, 1); break; case RSRC_DENIED: { AGpsExtType type = mBackwardCompatibleMode ? AGPS_TYPE_INVALID : mStateMachine->getType(); ((LocEngAdapter*)mLocAdapter)->atlOpenStatus(ID, 0, (char*)mStateMachine->getAPN(), mStateMachine->getBearer(), type); } break; case RSRC_GRANTED: { AGpsExtType type = mBackwardCompatibleMode ? AGPS_TYPE_INVALID : mStateMachine->getType(); ((LocEngAdapter*)mLocAdapter)->atlOpenStatus(ID, 1, (char*)mStateMachine->getAPN(), mStateMachine->getBearer(), type); } break; default: notify = false; } } return notify; } bool WIFISubscriber::notifyRsrcStatus(Notification ¬ification) { bool notify = forMe(notification); if (notify) { switch(notification.rsrcStatus) { case RSRC_UNSUBSCRIBE: break; case RSRC_RELEASED: loc_eng_dmn_conn_loc_api_server_data_conn( senderId, GPSONE_LOC_API_IF_RELEASE_SUCCESS); break; case RSRC_DENIED: loc_eng_dmn_conn_loc_api_server_data_conn( senderId, GPSONE_LOC_API_IF_FAILURE); break; case RSRC_GRANTED: loc_eng_dmn_conn_loc_api_server_data_conn( senderId, GPSONE_LOC_API_IF_REQUEST_SUCCESS); break; default: notify = false; } } return notify; } bool DSSubscriber::notifyRsrcStatus(Notification ¬ification) { bool notify = forMe(notification); LOC_LOGD("DSSubscriber::notifyRsrcStatus. notify:%d \n",(int)(notify)); if(notify) { switch(notification.rsrcStatus) { case RSRC_UNSUBSCRIBE: case RSRC_RELEASED: case RSRC_DENIED: case RSRC_GRANTED: ((DSStateMachine *)mStateMachine)->informStatus(notification.rsrcStatus, ID); break; default: notify = false; } } return notify; } void DSSubscriber :: setInactive() { mIsInactive = true; ((DSStateMachine *)mStateMachine)->informStatus(RSRC_UNSUBSCRIBE, ID); } //====================================================================== // AgpsState: AgpsReleasedState / AgpsPendingState / AgpsAcquiredState //====================================================================== // AgpsReleasedState class AgpsReleasedState : public AgpsState { friend class AgpsStateMachine; inline AgpsReleasedState(AgpsStateMachine* stateMachine) : AgpsState(stateMachine) { mReleasedState = this; } inline ~AgpsReleasedState() {} public: virtual AgpsState* onRsrcEvent(AgpsRsrcStatus event, void* data); inline virtual char* whoami() {return (char*)"AgpsReleasedState";} }; AgpsState* AgpsReleasedState::onRsrcEvent(AgpsRsrcStatus event, void* data) { LOC_LOGD("AgpsReleasedState::onRsrcEvent; event:%d\n", (int)event); if (mStateMachine->hasSubscribers()) { LOC_LOGE("Error: %s subscriber list not empty!!!", whoami()); // I don't know how to recover from it. I am adding this rather // for debugging purpose. } AgpsState* nextState = this; switch (event) { case RSRC_SUBSCRIBE: { // no notification until we get RSRC_GRANTED // but we need to add subscriber to the list mStateMachine->addSubscriber((Subscriber*)data); // request from connecivity service for NIF //The if condition 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(!mStateMachine->sendRsrcRequest(GPS_REQUEST_AGPS_DATA_CONN)) { // move the state to PENDING nextState = mPendingState; } } break; case RSRC_UNSUBSCRIBE: { // the list should really be empty, nothing to remove. // but we might as well just tell the client it is // unsubscribed. False tolerance, right? Subscriber* subscriber = (Subscriber*) data; Notification notification(subscriber, event, false); subscriber->notifyRsrcStatus(notification); } // break; case RSRC_GRANTED: case RSRC_RELEASED: case RSRC_DENIED: default: LOC_LOGW("%s: unrecognized event %d", whoami(), event); // no state change. break; } LOC_LOGD("onRsrcEvent, old state %s, new state %s, event %d", whoami(), nextState->whoami(), event); return nextState; } // AgpsPendingState class AgpsPendingState : public AgpsState { friend class AgpsStateMachine; inline AgpsPendingState(AgpsStateMachine* stateMachine) : AgpsState(stateMachine) { mPendingState = this; } inline ~AgpsPendingState() {} public: virtual AgpsState* onRsrcEvent(AgpsRsrcStatus event, void* data); inline virtual char* whoami() {return (char*)"AgpsPendingState";} }; AgpsState* AgpsPendingState::onRsrcEvent(AgpsRsrcStatus event, void* data) { AgpsState* nextState = this;; LOC_LOGD("AgpsPendingState::onRsrcEvent; event:%d\n", (int)event); switch (event) { case RSRC_SUBSCRIBE: { // already requested for NIF resource, // do nothing until we get RSRC_GRANTED indication // but we need to add subscriber to the list mStateMachine->addSubscriber((Subscriber*)data); // no state change. } break; case RSRC_UNSUBSCRIBE: { Subscriber* subscriber = (Subscriber*) data; if (subscriber->waitForCloseComplete()) { subscriber->setInactive(); } else { // auto notify this subscriber of the unsubscribe Notification notification(subscriber, event, true); mStateMachine->notifySubscribers(notification); } // now check if there is any subscribers left if (!mStateMachine->hasSubscribers()) { // no more subscribers, move to RELEASED state nextState = mReleasedState; // tell connecivity service we can release NIF mStateMachine->sendRsrcRequest(GPS_RELEASE_AGPS_DATA_CONN); } else if (!mStateMachine->hasActiveSubscribers()) { // only inactive subscribers, move to RELEASING state nextState = mReleasingState; // tell connecivity service we can release NIF mStateMachine->sendRsrcRequest(GPS_RELEASE_AGPS_DATA_CONN); } } break; case RSRC_GRANTED: { nextState = mAcquiredState; Notification notification(Notification::BROADCAST_ACTIVE, event, false); // notify all subscribers NIF resource GRANTED // by setting false, we keep subscribers on the linked list mStateMachine->notifySubscribers(notification); } break; case RSRC_RELEASED: // no state change. // we are expecting either GRANTED or DENIED. Handling RELEASED // may like break our state machine in race conditions. break; case RSRC_DENIED: { nextState = mReleasedState; Notification notification(Notification::BROADCAST_ALL, event, true); // notify all subscribers NIF resource RELEASED or DENIED // by setting true, we remove subscribers from the linked list mStateMachine->notifySubscribers(notification); } break; default: LOC_LOGE("%s: unrecognized event %d", whoami(), event); // no state change. } LOC_LOGD("onRsrcEvent, old state %s, new state %s, event %d", whoami(), nextState->whoami(), event); return nextState; } class AgpsAcquiredState : public AgpsState { friend class AgpsStateMachine; inline AgpsAcquiredState(AgpsStateMachine* stateMachine) : AgpsState(stateMachine) { mAcquiredState = this; } inline ~AgpsAcquiredState() {} public: virtual AgpsState* onRsrcEvent(AgpsRsrcStatus event, void* data); inline virtual char* whoami() { return (char*)"AgpsAcquiredState"; } }; AgpsState* AgpsAcquiredState::onRsrcEvent(AgpsRsrcStatus event, void* data) { AgpsState* nextState = this; LOC_LOGD("AgpsAcquiredState::onRsrcEvent; event:%d\n", (int)event); switch (event) { case RSRC_SUBSCRIBE: { // we already have the NIF resource, simply notify subscriber Subscriber* subscriber = (Subscriber*) data; // we have rsrc in hand, so grant it right away Notification notification(subscriber, RSRC_GRANTED, false); subscriber->notifyRsrcStatus(notification); // add subscriber to the list mStateMachine->addSubscriber(subscriber); // no state change. } break; case RSRC_UNSUBSCRIBE: { Subscriber* subscriber = (Subscriber*) data; if (subscriber->waitForCloseComplete()) { subscriber->setInactive(); } else { // auto notify this subscriber of the unsubscribe Notification notification(subscriber, event, true); mStateMachine->notifySubscribers(notification); } // now check if there is any subscribers left if (!mStateMachine->hasSubscribers()) { // no more subscribers, move to RELEASED state nextState = mReleasedState; // tell connecivity service we can release NIF mStateMachine->sendRsrcRequest(GPS_RELEASE_AGPS_DATA_CONN); } else if (!mStateMachine->hasActiveSubscribers()) { // only inactive subscribers, move to RELEASING state nextState = mReleasingState; // tell connecivity service we can release NIF mStateMachine->sendRsrcRequest(GPS_RELEASE_AGPS_DATA_CONN); } } break; case RSRC_GRANTED: LOC_LOGW("%s: %d, RSRC_GRANTED already received", whoami(), event); // no state change. break; case RSRC_RELEASED: { LOC_LOGW("%s: %d, a force rsrc release", whoami(), event); nextState = mReleasedState; Notification notification(Notification::BROADCAST_ALL, event, true); // by setting true, we remove subscribers from the linked list mStateMachine->notifySubscribers(notification); } break; case RSRC_DENIED: // no state change. // we are expecting RELEASED. Handling DENIED // may like break our state machine in race conditions. break; default: LOC_LOGE("%s: unrecognized event %d", whoami(), event); // no state change. } LOC_LOGD("onRsrcEvent, old state %s, new state %s, event %d", whoami(), nextState->whoami(), event); return nextState; } // AgpsPendingState class AgpsReleasingState : public AgpsState { friend class AgpsStateMachine; inline AgpsReleasingState(AgpsStateMachine* stateMachine) : AgpsState(stateMachine) { mReleasingState = this; } inline ~AgpsReleasingState() {} public: virtual AgpsState* onRsrcEvent(AgpsRsrcStatus event, void* data); inline virtual char* whoami() {return (char*)"AgpsReleasingState";} }; AgpsState* AgpsReleasingState::onRsrcEvent(AgpsRsrcStatus event, void* data) { AgpsState* nextState = this;; LOC_LOGD("AgpsReleasingState::onRsrcEvent; event:%d\n", (int)event); switch (event) { case RSRC_SUBSCRIBE: { // already requested for NIF resource, // do nothing until we get RSRC_GRANTED indication // but we need to add subscriber to the list mStateMachine->addSubscriber((Subscriber*)data); // no state change. } break; case RSRC_UNSUBSCRIBE: { Subscriber* subscriber = (Subscriber*) data; if (subscriber->waitForCloseComplete()) { subscriber->setInactive(); } else { // auto notify this subscriber of the unsubscribe Notification notification(subscriber, event, true); mStateMachine->notifySubscribers(notification); } // now check if there is any subscribers left if (!mStateMachine->hasSubscribers()) { // no more subscribers, move to RELEASED state nextState = mReleasedState; } } break; case RSRC_DENIED: // A race condition subscriber unsubscribes before AFW denies resource. case RSRC_RELEASED: { nextState = mAcquiredState; Notification notification(Notification::BROADCAST_INACTIVE, event, true); // notify all subscribers that are active NIF resource RELEASE // by setting false, we keep subscribers on the linked list mStateMachine->notifySubscribers(notification); if (mStateMachine->hasActiveSubscribers()) { nextState = mPendingState; // request from connecivity service for NIF mStateMachine->sendRsrcRequest(GPS_REQUEST_AGPS_DATA_CONN); } else { nextState = mReleasedState; } } break; case RSRC_GRANTED: default: LOC_LOGE("%s: unrecognized event %d", whoami(), event); // no state change. } LOC_LOGD("onRsrcEvent, old state %s, new state %s, event %d", whoami(), nextState->whoami(), event); return nextState; } //====================================================================== //Servicer //====================================================================== Servicer* Servicer :: getServicer(servicerType type, void *cb_func) { LOC_LOGD(" Enter getServicer type:%d\n", (int)type); switch(type) { case servicerTypeNoCbParam: return (new Servicer(cb_func)); case servicerTypeExt: return (new ExtServicer(cb_func)); case servicerTypeAgps: return (new AGpsServicer(cb_func)); default: return NULL; } } int Servicer :: requestRsrc(void *cb_data) { callback(); return 0; } int ExtServicer :: requestRsrc(void *cb_data) { int ret=-1; LOC_LOGD("Enter ExtServicer :: requestRsrc\n"); ret = callbackExt(cb_data); LOC_LOGD("Exit ExtServicer :: requestRsrc\n"); return(ret); } int AGpsServicer :: requestRsrc(void *cb_data) { callbackAGps((AGpsStatus *)cb_data); return 0; } //====================================================================== // AgpsStateMachine //====================================================================== AgpsStateMachine::AgpsStateMachine(servicerType servType, void *cb_func, AGpsExtType type, bool enforceSingleSubscriber) : mStatePtr(new AgpsReleasedState(this)),mType(type), mAPN(NULL), mAPNLen(0), mBearer(AGPS_APN_BEARER_INVALID), mEnforceSingleSubscriber(enforceSingleSubscriber), mServicer(Servicer :: getServicer(servType, (void *)cb_func)) { linked_list_init(&mSubscribers); // setting up mReleasedState mStatePtr->mPendingState = new AgpsPendingState(this); mStatePtr->mAcquiredState = new AgpsAcquiredState(this); mStatePtr->mReleasingState = new AgpsReleasingState(this); // setting up mAcquiredState mStatePtr->mAcquiredState->mReleasedState = mStatePtr; mStatePtr->mAcquiredState->mPendingState = mStatePtr->mPendingState; mStatePtr->mAcquiredState->mReleasingState = mStatePtr->mReleasingState; // setting up mPendingState mStatePtr->mPendingState->mAcquiredState = mStatePtr->mAcquiredState; mStatePtr->mPendingState->mReleasedState = mStatePtr; mStatePtr->mPendingState->mReleasingState = mStatePtr->mReleasingState; // setting up mReleasingState mStatePtr->mReleasingState->mReleasedState = mStatePtr; mStatePtr->mReleasingState->mPendingState = mStatePtr->mPendingState; mStatePtr->mReleasingState->mAcquiredState = mStatePtr->mAcquiredState; } AgpsStateMachine::~AgpsStateMachine() { dropAllSubscribers(); // free the 3 states. We must read out all 3 pointers first. // Otherwise we run the risk of getting pointers from already // freed memory. AgpsState* acquiredState = mStatePtr->mAcquiredState; AgpsState* releasedState = mStatePtr->mReleasedState; AgpsState* pendindState = mStatePtr->mPendingState; AgpsState* releasingState = mStatePtr->mReleasingState; delete acquiredState; delete releasedState; delete pendindState; delete releasingState; delete mServicer; linked_list_destroy(&mSubscribers); if (NULL != mAPN) { delete[] mAPN; mAPN = NULL; } } void AgpsStateMachine::setAPN(const char* apn, unsigned int len) { if (NULL != mAPN) { delete mAPN; } if (NULL != apn) { mAPN = new char[len+1]; memcpy(mAPN, apn, len); mAPN[len] = NULL; mAPNLen = len; } else { mAPN = NULL; mAPNLen = 0; } } void AgpsStateMachine::onRsrcEvent(AgpsRsrcStatus event) { switch (event) { case RSRC_GRANTED: case RSRC_RELEASED: case RSRC_DENIED: mStatePtr = mStatePtr->onRsrcEvent(event, NULL); break; default: LOC_LOGW("AgpsStateMachine: unrecognized event %d", event); break; } } void AgpsStateMachine::notifySubscribers(Notification& notification) const { if (notification.postNotifyDelete) { // just any non NULL value to get started Subscriber* s = (Subscriber*)~0; while (NULL != s) { s = NULL; // if the last param sets to true, _search will delete // the node from the list for us. But the problem is // once that is done, _search returns, leaving the // rest of the list unprocessed. So we need a loop. linked_list_search(mSubscribers, (void**)&s, notifySubscriber, (void*)¬ification, true); delete s; } } else { // no loop needed if it the last param sets to false, which // mean nothing gets deleted from the list. linked_list_search(mSubscribers, NULL, notifySubscriber, (void*)¬ification, false); } } void AgpsStateMachine::addSubscriber(Subscriber* subscriber) const { Subscriber* s = NULL; Notification notification((const Subscriber*)subscriber); linked_list_search(mSubscribers, (void**)&s, hasSubscriber, (void*)¬ification, false); if (NULL == s) { linked_list_add(mSubscribers, subscriber->clone(), deleteObj); } } int AgpsStateMachine::sendRsrcRequest(AGpsStatusValue action) const { Subscriber* s = NULL; Notification notification(Notification::BROADCAST_ACTIVE); linked_list_search(mSubscribers, (void**)&s, hasSubscriber, (void*)¬ification, false); if ((NULL == s) == (GPS_RELEASE_AGPS_DATA_CONN == action)) { AGpsExtStatus nifRequest; nifRequest.size = sizeof(nifRequest); nifRequest.type = mType; nifRequest.status = action; if (s == NULL) { nifRequest.ipv4_addr = INADDR_NONE; memset(&nifRequest.addr, 0, sizeof(nifRequest.addr)); nifRequest.ssid[0] = '\0'; nifRequest.password[0] = '\0'; } else { s->setIPAddresses(nifRequest.addr); s->setWifiInfo(nifRequest.ssid, nifRequest.password); } CALLBACK_LOG_CALLFLOW("agps_cb", %s, loc_get_agps_status_name(action)); mServicer->requestRsrc((void *)&nifRequest); } return 0; } void AgpsStateMachine::subscribeRsrc(Subscriber *subscriber) { if (mEnforceSingleSubscriber && hasSubscribers()) { Notification notification(Notification::BROADCAST_ALL, RSRC_DENIED, true); notifySubscriber(¬ification, subscriber); } else { mStatePtr = mStatePtr->onRsrcEvent(RSRC_SUBSCRIBE, (void*)subscriber); } } bool AgpsStateMachine::unsubscribeRsrc(Subscriber *subscriber) { Subscriber* s = NULL; Notification notification((const Subscriber*)subscriber); linked_list_search(mSubscribers, (void**)&s, hasSubscriber, (void*)¬ification, false); if (NULL != s) { mStatePtr = mStatePtr->onRsrcEvent(RSRC_UNSUBSCRIBE, (void*)s); return true; } return false; } bool AgpsStateMachine::hasActiveSubscribers() const { Subscriber* s = NULL; Notification notification(Notification::BROADCAST_ACTIVE); linked_list_search(mSubscribers, (void**)&s, hasSubscriber, (void*)¬ification, false); return NULL != s; } //====================================================================== // DSStateMachine //====================================================================== void delay_callback(void *callbackData, int result) { if(callbackData) { DSStateMachine *DSSMInstance = (DSStateMachine *)callbackData; DSSMInstance->retryCallback(); } else { LOC_LOGE(" NULL argument received. Failing.\n"); goto err; } err: return; } DSStateMachine :: DSStateMachine(servicerType type, void *cb_func, LocEngAdapter* adapterHandle): AgpsStateMachine(type, cb_func, AGPS_TYPE_INVALID,false), mLocAdapter(adapterHandle) { LOC_LOGD("%s:%d]: New DSStateMachine\n", __func__, __LINE__); mRetries = 0; } void DSStateMachine :: retryCallback(void) { DSSubscriber *subscriber = NULL; Notification notification(Notification::BROADCAST_ACTIVE); linked_list_search(mSubscribers, (void**)&subscriber, hasSubscriber, (void*)¬ification, false); if(subscriber) mLocAdapter->requestSuplES(subscriber->ID); else LOC_LOGE("DSStateMachine :: retryCallback: No subscriber found." \ "Cannot retry data call\n"); return; } int DSStateMachine :: sendRsrcRequest(AGpsStatusValue action) const { DSSubscriber* s = NULL; dsCbData cbData; int ret=-1; int connHandle=-1; LOC_LOGD("Enter DSStateMachine :: sendRsrcRequest\n"); Notification notification(Notification::BROADCAST_ACTIVE); linked_list_search(mSubscribers, (void**)&s, hasSubscriber, (void*)¬ification, false); if(s) { connHandle = s->ID; LOC_LOGD("DSStateMachine :: sendRsrcRequest - subscriber found\n"); } else LOC_LOGD("DSStateMachine :: sendRsrcRequest - No subscriber found\n"); cbData.action = action; cbData.mAdapter = mLocAdapter; ret = mServicer->requestRsrc((void *)&cbData); //Only the request to start data call returns a success/failure //The request to stop data call will always succeed //Hence, the below block will only be executed when the //request to start the data call fails switch(ret) { case LOC_API_ADAPTER_ERR_ENGINE_BUSY: LOC_LOGD("DSStateMachine :: sendRsrcRequest - Failure returned: %d\n",ret); ((DSStateMachine *)this)->incRetries(); if(mRetries > MAX_START_DATA_CALL_RETRIES) { LOC_LOGE(" Failed to start Data call. Fallback to normal ATL SUPL\n"); informStatus(RSRC_DENIED, connHandle); } else { if(loc_timer_start(DATA_CALL_RETRY_DELAY_MSEC, delay_callback, (void *)this)) { LOC_LOGE("Error: Could not start delay thread\n"); ret = -1; goto err; } } break; case LOC_API_ADAPTER_ERR_UNSUPPORTED: LOC_LOGE("No profile found for emergency call. Fallback to normal SUPL ATL\n"); informStatus(RSRC_DENIED, connHandle); break; case LOC_API_ADAPTER_ERR_SUCCESS: LOC_LOGD("%s:%d]: Request to start data call sent\n", __func__, __LINE__); break; case -1: //One of the ways this case can be encountered is if the callback function //receives a null argument, it just exits with -1 error LOC_LOGE("Error: Something went wrong somewhere. Falling back to normal SUPL ATL\n"); informStatus(RSRC_DENIED, connHandle); break; default: LOC_LOGE("%s:%d]: Unrecognized return value\n", __func__, __LINE__); } err: LOC_LOGD("EXIT DSStateMachine :: sendRsrcRequest; ret = %d\n", ret); return ret; } void DSStateMachine :: onRsrcEvent(AgpsRsrcStatus event) { void* currState = (void *)mStatePtr; LOC_LOGD("Enter DSStateMachine :: onRsrcEvent. event = %d\n", (int)event); switch (event) { case RSRC_GRANTED: LOC_LOGD("DSStateMachine :: onRsrcEvent RSRC_GRANTED\n"); mStatePtr = mStatePtr->onRsrcEvent(event, NULL); break; case RSRC_RELEASED: LOC_LOGD("DSStateMachine :: onRsrcEvent RSRC_RELEASED\n"); mStatePtr = mStatePtr->onRsrcEvent(event, NULL); //To handle the case where we get a RSRC_RELEASED in //pending state, we translate that to a RSRC_DENIED state //since the callback from DSI is either RSRC_GRANTED or RSRC_RELEASED //for when the call is connected or disconnected respectively. if((void *)mStatePtr != currState) break; else { event = RSRC_DENIED; LOC_LOGE(" Switching event to RSRC_DENIED\n"); } case RSRC_DENIED: mStatePtr = mStatePtr->onRsrcEvent(event, NULL); break; default: LOC_LOGW("AgpsStateMachine: unrecognized event %d", event); break; } LOC_LOGD("Exit DSStateMachine :: onRsrcEvent. event = %d\n", (int)event); } void DSStateMachine :: informStatus(AgpsRsrcStatus status, int ID) const { LOC_LOGD("DSStateMachine :: informStatus. Status=%d\n",(int)status); switch(status) { case RSRC_UNSUBSCRIBE: mLocAdapter->atlCloseStatus(ID, 1); break; case RSRC_RELEASED: mLocAdapter->closeDataCall(); break; case RSRC_DENIED: ((DSStateMachine *)this)->mRetries = 0; mLocAdapter->requestATL(ID, AGPS_TYPE_SUPL); break; case RSRC_GRANTED: mLocAdapter->atlOpenStatus(ID, 1, NULL, AGPS_APN_BEARER_INVALID, AGPS_TYPE_INVALID); break; default: LOC_LOGW("DSStateMachine :: informStatus - unknown status"); } return; }