code:
/* Copyright (c) 2012-2019, 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_NDEBUG 0
#define LOG_TAG "LocSvc_Agps"

#include <Agps.h>
#include <loc_pla.h>
#include <ContextBase.h>
#include <loc_timer.h>
#include <inttypes.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);
            requestOrReleaseDataConn(true);
            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 */
void AgpsStateMachine::requestOrReleaseDataConn(bool request){

    AGnssExtStatusIpV4 nifRequest;
    memset(&nifRequest, 0, sizeof(nifRequest));

    nifRequest.type = mAgpsType;
    nifRequest.apnTypeMask = mApnTypeMask;
    if (request) {
        LOC_LOGD("AGPS Data Conn Request mAgpsType=%d mApnTypeMask=0x%X",
                 mAgpsType, mApnTypeMask);
        nifRequest.status = LOC_GPS_REQUEST_AGPS_DATA_CONN;
    }
    else{
        LOC_LOGD("AGPS Data Conn Release mAgpsType=%d mApnTypeMask=0x%X",
                 mAgpsType, mApnTypeMask);
        nifRequest.status = LOC_GPS_RELEASE_AGPS_DATA_CONN;
    }

    mFrameworkStatusV4Cb(nifRequest);
}

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(), getAPNLen(),
                    getBearer(), mAgpsType, mApnTypeMask);
            break;

        case AGPS_EVENT_DENIED:
            mAgpsManager->mAtlOpenStatusCb(
                    subscriberToNotify->mConnHandle, 0, getAPN(), getAPNLen(),
                    getBearer(), mAgpsType, mApnTypeMask);
            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;
        mAPN  = NULL;
    }

    if (NULL == apn || len > MAX_APN_LEN || strlen(apn) != len) {
        LOC_LOGD("Invalid apn len (%d) or null apn", len);
        mAPN = NULL;
        mAPNLen = 0;
    } else {
        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;
    }
}

/* --------------------------------------------------------------------
 *   Loc AGPS Manager Methods
 * -------------------------------------------------------------------*/

/* CREATE AGPS STATE MACHINES
 * Must be invoked in Msg Handler context */
void AgpsManager::createAgpsStateMachines(const AgpsCbInfo& cbInfo) {

    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 && (cbInfo.atlType & AGPS_ATL_TYPE_WWAN)) {
        mInternetNif = new AgpsStateMachine(this, LOC_AGPS_TYPE_WWAN_ANY);
        mInternetNif->registerFrameworkStatusCallback((AgnssStatusIpV4Cb)cbInfo.statusV4Cb);
        LOC_LOGD("Internet NIF: %p", mInternetNif);
    }
    if (agpsCapable) {
        if (NULL == mAgnssNif && (cbInfo.atlType & AGPS_ATL_TYPE_SUPL) &&
                (cbInfo.atlType & AGPS_ATL_TYPE_SUPL_ES)) {
            mAgnssNif = new AgpsStateMachine(this, LOC_AGPS_TYPE_SUPL);
            mAgnssNif->registerFrameworkStatusCallback((AgnssStatusIpV4Cb)cbInfo.statusV4Cb);
            LOC_LOGD("AGNSS NIF: %p", mAgnssNif);
        }
    }
}

AgpsStateMachine* AgpsManager::getAgpsStateMachine(AGpsExtType agpsType) {

    LOC_LOGD("AgpsManager::getAgpsStateMachine(): agpsType %d", agpsType);

    switch (agpsType) {

        case LOC_AGPS_TYPE_INVALID:
        case LOC_AGPS_TYPE_SUPL:
        case LOC_AGPS_TYPE_SUPL_ES:
            if (mAgnssNif == NULL) {
                LOC_LOGE("NULL AGNSS NIF !");
            }
            return mAgnssNif;
        case LOC_AGPS_TYPE_WWAN_ANY:
            if (mInternetNif == NULL) {
                LOC_LOGE("NULL Internet NIF !");
            }
            return mInternetNif;
        default:
            return mInternetNif;
    }

    LOC_LOGE("No SM found !");
    return NULL;
}

void AgpsManager::requestATL(int connHandle, AGpsExtType agpsType,
                             LocApnTypeMask apnTypeMask){

    LOC_LOGD("AgpsManager::requestATL(): connHandle %d, agpsType 0x%X apnTypeMask: 0x%X",
               connHandle, agpsType, apnTypeMask);

    if (0 == loc_core::ContextBase::mGps_conf.USE_EMERGENCY_PDN_FOR_EMERGENCY_SUPL &&
        LOC_AGPS_TYPE_SUPL_ES == agpsType) {
        agpsType = LOC_AGPS_TYPE_SUPL;
        apnTypeMask &= ~LOC_APN_TYPE_MASK_EMERGENCY;
        apnTypeMask |= LOC_APN_TYPE_MASK_SUPL;
        LOC_LOGD("Changed agpsType to non-emergency when USE_EMERGENCY... is 0"
                 "and removed LOC_APN_TYPE_MASK_EMERGENCY from apnTypeMask"
                 "agpsType 0x%X apnTypeMask : 0x%X",
                 agpsType, apnTypeMask);
    }
    AgpsStateMachine* sm = getAgpsStateMachine(agpsType);

    if (sm == NULL) {

        LOC_LOGE("No AGPS State Machine for agpsType: %d apnTypeMask: 0x%X",
                 agpsType, apnTypeMask);
        mAtlOpenStatusCb(
                connHandle, 0, NULL, 0, AGPS_APN_BEARER_INVALID, agpsType, apnTypeMask);
        return;
    }
    sm->setType(agpsType);
    sm->setApnTypeMask(apnTypeMask);

    /* Invoke AGPS SM processing */
    AgpsSubscriber subscriber(connHandle, true, false, apnTypeMask);
    sm->setCurrentSubscriber(&subscriber);
    /* 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;
    }
    if (sm == NULL) {
        LOC_LOGE("Subscriber with connHandle %d not found in any SM",
                    connHandle);
        return;
    }

    /* Now send unsubscribe event */
    sm->setCurrentSubscriber(subscriber);
    sm->processAgpsEvent(AGPS_EVENT_UNSUBSCRIBE);
}

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();
    }
}


code:
/* Copyright (c) 2012-2018, 2020 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 <loc_pla.h>
#include <log_util.h>

using namespace loc_util;

/* ATL callback function pointers
 * Passed in by Adapter to AgpsManager */
typedef std::function<void(
        int handle, int isSuccess, char* apn, uint32_t apnLen,
        AGpsBearerType bearerType, AGpsExtType agpsType,
        LocApnTypeMask mask)> AgpsAtlOpenStatusCb;

typedef std::function<void(int handle, int isSuccess)> AgpsAtlCloseStatusCb;

/* 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;

/* Classes in this header */
class AgpsSubscriber;
class AgpsManager;
class AgpsStateMachine;

/* 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;
    LocApnTypeMask mApnTypeMask;

    inline AgpsSubscriber(
            int connHandle, bool waitForCloseComplete, bool isInactive,
            LocApnTypeMask apnTypeMask) :
            mConnHandle(connHandle),
            mWaitForCloseComplete(waitForCloseComplete),
            mIsInactive(isInactive),
            mApnTypeMask(apnTypeMask) {}
    inline virtual ~AgpsSubscriber() {}

    inline virtual bool equals(const AgpsSubscriber *s) const
    { return (mConnHandle == s->mConnHandle); }

    inline virtual AgpsSubscriber* clone()
    { return new AgpsSubscriber(
            mConnHandle, mWaitForCloseComplete, mIsInactive, mApnTypeMask); }
};

/* 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;

    AgnssStatusIpV4Cb     mFrameworkStatusV4Cb;
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;
    LocApnTypeMask mApnTypeMask;

    /* APN and IP Type info for AGPS Call */
    char* mAPN;
    unsigned int mAPNLen;
    AGpsBearerType mBearer;

public:
    /* CONSTRUCTOR */
    AgpsStateMachine(AgpsManager* agpsManager, AGpsExtType agpsType):
        mFrameworkStatusV4Cb(NULL),
        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 mAPN; }
    inline uint32_t getAPNLen() const { return mAPNLen; }
    inline void setBearer(AGpsBearerType bearer) { mBearer = bearer; }
    inline LocApnTypeMask getApnTypeMask() const { return mApnTypeMask; }
    inline void setApnTypeMask(LocApnTypeMask apnTypeMask)
    { mApnTypeMask = apnTypeMask; }
    inline AGpsBearerType getBearer() const { return mBearer; }
    inline void setType(AGpsExtType type) { mAgpsType = type; }
    inline AGpsExtType getType() const { return mAgpsType; }
    inline void setCurrentSubscriber(AgpsSubscriber* subscriber)
    { mCurrentSubscriber = subscriber; }

    inline void registerFrameworkStatusCallback(AgnssStatusIpV4Cb frameworkStatusV4Cb) {
        mFrameworkStatusV4Cb = frameworkStatusV4Cb;
    }

    /* 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) */
    void 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);
};

/* LOC AGPS MANAGER */
class AgpsManager {

    friend class AgpsStateMachine;
public:
    /* CONSTRUCTOR */
    AgpsManager():
        mAtlOpenStatusCb(), mAtlCloseStatusCb(),
        mAgnssNif(NULL), mInternetNif(NULL)/*, mDsNif(NULL)*/ {}

    /* Register callbacks */
    inline void registerATLCallbacks(AgpsAtlOpenStatusCb  atlOpenStatusCb,
            AgpsAtlCloseStatusCb                atlCloseStatusCb) {

        mAtlOpenStatusCb = atlOpenStatusCb;
        mAtlCloseStatusCb = atlCloseStatusCb;
    }

    /* Check if AGPS client is registered */
    inline bool isRegistered() { return nullptr != mAgnssNif || nullptr != mInternetNif; }

    /* Create all AGPS state machines */
    void createAgpsStateMachines(const AgpsCbInfo& cbInfo);

    /* Process incoming ATL requests */
    void requestATL(int connHandle, AGpsExtType agpsType, LocApnTypeMask apnTypeMask);
    void releaseATL(int connHandle);
    /* Process incoming framework data call events */
    void reportAtlOpenSuccess(AGpsExtType agpsType, char* apnName, int apnLen,
            AGpsBearerType bearerType);
    void reportAtlOpenFailed(AGpsExtType agpsType);
    void reportAtlClosed(AGpsExtType agpsType);

    /* Handle Modem SSR */
    void handleModemSSR();

protected:

    AgpsAtlOpenStatusCb   mAtlOpenStatusCb;
    AgpsAtlCloseStatusCb  mAtlCloseStatusCb;
    AgpsStateMachine*   mAgnssNif;
    AgpsStateMachine*   mInternetNif;
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;
    LocApnTypeMask mApnTypeMask;

    inline AgpsMsgRequestATL(AgpsManager* agpsManager, int connHandle,
            AGpsExtType agpsType, LocApnTypeMask apnTypeMask) :
            LocMsg(), mAgpsManager(agpsManager), mConnHandle(connHandle),
            mAgpsType(agpsType), mApnTypeMask(apnTypeMask){

        LOC_LOGV("AgpsMsgRequestATL");
    }

    inline virtual void proc() const {

        LOC_LOGV("AgpsMsgRequestATL::proc()");
        mAgpsManager->requestATL(mConnHandle, mAgpsType, mApnTypeMask);
    }
};

namespace AgpsUtils {

AGpsBearerType ipTypeToBearerType(LocApnIpType ipType);
LocApnIpType bearerTypeToIpType(AGpsBearerType bearerType);

}

#endif /* AGPS_H */

license: unknown


code:
cc_library_shared {

    name: "libgnss",
    vendor: true,

    shared_libs: [
        "libutils",
        "libcutils",
        "libdl",
        "liblog",
        "libloc_core",
        "libgps.utils",
    ],

    srcs: [
        "location_gnss.cpp",
        "GnssAdapter.cpp",
        "Agps.cpp",
        "XtraSystemStatusObserver.cpp",
        "NativeAgpsHandler.cpp",
    ],

    cflags: ["-fno-short-enums"] + GNSS_CFLAGS,
    header_libs: [
        "libgps.utils_headers",
        "libloc_core_headers",
        "libloc_pla_headers",
        "liblocation_api_headers",
    ],

}