Home | History | Annotate | Download | only in libloc_api_50001
      1 /* Copyright (c) 2009-2014, The Linux Foundation. All rights reserved.
      2  *
      3  * Redistribution and use in source and binary forms, with or without
      4  * modification, are permitted provided that the following conditions are
      5  * met:
      6  *     * Redistributions of source code must retain the above copyright
      7  *       notice, this list of conditions and the following disclaimer.
      8  *     * Redistributions in binary form must reproduce the above
      9  *       copyright notice, this list of conditions and the following
     10  *       disclaimer in the documentation and/or other materials provided
     11  *       with the distribution.
     12  *     * Neither the name of The Linux Foundation, nor the names of its
     13  *       contributors may be used to endorse or promote products derived
     14  *       from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  *
     28  */
     29 
     30 #define LOG_NDDEBUG 0
     31 #define LOG_TAG "LocSvc_eng"
     32 
     33 #include <stdio.h>
     34 #include <stdlib.h>
     35 #include <sys/time.h>
     36 #include <pthread.h>
     37 #include <errno.h>
     38 #include <string.h>
     39 #include <ctype.h>
     40 #include <unistd.h>
     41 #include <time.h>
     42 #include <MsgTask.h>
     43 
     44 #include <loc_eng.h>
     45 
     46 #include "log_util.h"
     47 #include "platform_lib_includes.h"
     48 
     49 using namespace loc_core;
     50 
     51 /*=============================================================================
     52  *
     53  *                             DATA DECLARATION
     54  *
     55  *============================================================================*/
     56 
     57 /*=============================================================================
     58  *
     59  *                             FUNCTION DECLARATIONS
     60  *
     61  *============================================================================*/
     62 static void* ni_thread_proc(void *args);
     63 
     64 struct LocEngInformNiResponse : public LocMsg {
     65     LocEngAdapter* mAdapter;
     66     const GpsUserResponseType mResponse;
     67     const void *mPayload;
     68     inline LocEngInformNiResponse(LocEngAdapter* adapter,
     69                                   GpsUserResponseType resp,
     70                                   const void* data) :
     71         LocMsg(), mAdapter(adapter),
     72         mResponse(resp), mPayload(data)
     73     {
     74         locallog();
     75     }
     76     inline ~LocEngInformNiResponse()
     77     {
     78         // this is a bit weird since mPayload is not
     79         // allocated by this class.  But there is no better way.
     80         // mPayload actually won't be NULL here.
     81         free((void*)mPayload);
     82     }
     83     inline virtual void proc() const
     84     {
     85         mAdapter->informNiResponse(mResponse, mPayload);
     86     }
     87     inline void locallog() const
     88     {
     89         LOC_LOGV("LocEngInformNiResponse - "
     90                  "response: %s\n  mPayload: %p",
     91                  loc_get_ni_response_name(mResponse),
     92                  mPayload);
     93     }
     94     inline virtual void log() const
     95     {
     96         locallog();
     97     }
     98 };
     99 
    100 /*===========================================================================
    101 
    102 FUNCTION loc_eng_ni_request_handler
    103 
    104 DESCRIPTION
    105    Displays the NI request and awaits user input. If a previous request is
    106    in session, it is ignored.
    107 
    108 RETURN VALUE
    109    none
    110 
    111 ===========================================================================*/
    112 void loc_eng_ni_request_handler(loc_eng_data_s_type &loc_eng_data,
    113                             const GpsNiNotification *notif,
    114                             const void* passThrough)
    115 {
    116     ENTRY_LOG();
    117     char lcs_addr[32]; // Decoded LCS address for UMTS CP NI
    118     loc_eng_ni_data_s_type* loc_eng_ni_data_p = &loc_eng_data.loc_eng_ni_data;
    119     loc_eng_ni_session_s_type* pSession = NULL;
    120 
    121     if (NULL == loc_eng_data.ni_notify_cb) {
    122         EXIT_LOG(%s, "loc_eng_ni_init hasn't happened yet.");
    123         return;
    124     }
    125 
    126     if (notif->ni_type == GPS_NI_TYPE_EMERGENCY_SUPL) {
    127         if (NULL != loc_eng_ni_data_p->sessionEs.rawRequest) {
    128             LOC_LOGW("loc_eng_ni_request_handler, supl es NI in progress, new supl es NI ignored, type: %d",
    129                      notif->ni_type);
    130             if (NULL != passThrough) {
    131                 free((void*)passThrough);
    132             }
    133         } else {
    134             pSession = &loc_eng_ni_data_p->sessionEs;
    135         }
    136     } else {
    137         if (NULL != loc_eng_ni_data_p->session.rawRequest ||
    138             NULL != loc_eng_ni_data_p->sessionEs.rawRequest) {
    139             LOC_LOGW("loc_eng_ni_request_handler, supl NI in progress, new supl NI ignored, type: %d",
    140                      notif->ni_type);
    141             if (NULL != passThrough) {
    142                 free((void*)passThrough);
    143             }
    144         } else {
    145             pSession = &loc_eng_ni_data_p->session;
    146         }
    147     }
    148 
    149 
    150     if (pSession) {
    151         /* Save request */
    152         pSession->rawRequest = (void*)passThrough;
    153         pSession->reqID = ++loc_eng_ni_data_p->reqIDCounter;
    154         pSession->adapter = loc_eng_data.adapter;
    155 
    156         /* Fill in notification */
    157         ((GpsNiNotification*)notif)->notification_id = pSession->reqID;
    158 
    159         if (notif->notify_flags == GPS_NI_PRIVACY_OVERRIDE)
    160         {
    161             loc_eng_mute_one_session(loc_eng_data);
    162         }
    163 
    164         /* Log requestor ID and text for debugging */
    165         LOC_LOGI("Notification: notif_type: %d, timeout: %d, default_resp: %d", notif->ni_type, notif->timeout, notif->default_response);
    166         LOC_LOGI("              requestor_id: %s (encoding: %d)", notif->requestor_id, notif->requestor_id_encoding);
    167         LOC_LOGI("              text: %s text (encoding: %d)", notif->text, notif->text_encoding);
    168         if (notif->extras[0])
    169         {
    170             LOC_LOGI("              extras: %s", notif->extras);
    171         }
    172 
    173         /* For robustness, spawn a thread at this point to timeout to clear up the notification status, even though
    174          * the OEM layer in java does not do so.
    175          **/
    176         pSession->respTimeLeft = 5 + (notif->timeout != 0 ? notif->timeout : LOC_NI_NO_RESPONSE_TIME);
    177         LOC_LOGI("Automatically sends 'no response' in %d seconds (to clear status)\n", pSession->respTimeLeft);
    178 
    179         int rc = 0;
    180         rc = pthread_create(&pSession->thread, NULL, ni_thread_proc, pSession);
    181         if (rc)
    182         {
    183             LOC_LOGE("Loc NI thread is not created.\n");
    184         }
    185         rc = pthread_detach(pSession->thread);
    186         if (rc)
    187         {
    188             LOC_LOGE("Loc NI thread is not detached.\n");
    189         }
    190 
    191         CALLBACK_LOG_CALLFLOW("ni_notify_cb - id", %d, notif->notification_id);
    192         loc_eng_data.ni_notify_cb((GpsNiNotification*)notif);
    193     }
    194     EXIT_LOG(%s, VOID_RET);
    195 }
    196 
    197 /*===========================================================================
    198 
    199 FUNCTION ni_thread_proc
    200 
    201 ===========================================================================*/
    202 static void* ni_thread_proc(void *args)
    203 {
    204     ENTRY_LOG();
    205 
    206     loc_eng_ni_session_s_type* pSession = (loc_eng_ni_session_s_type*)args;
    207     int rc = 0;          /* return code from pthread calls */
    208 
    209     struct timeval present_time;
    210     struct timespec expire_time;
    211 
    212     LOC_LOGD("Starting Loc NI thread...\n");
    213     pthread_mutex_lock(&pSession->tLock);
    214     /* Calculate absolute expire time */
    215     gettimeofday(&present_time, NULL);
    216     expire_time.tv_sec  = present_time.tv_sec + pSession->respTimeLeft;
    217     expire_time.tv_nsec = present_time.tv_usec * 1000;
    218     LOC_LOGD("ni_thread_proc-Time out set for abs time %ld with delay %d sec\n",
    219              (long) expire_time.tv_sec, pSession->respTimeLeft );
    220 
    221     while (!pSession->respRecvd)
    222     {
    223         rc = pthread_cond_timedwait(&pSession->tCond,
    224                                     &pSession->tLock,
    225                                     &expire_time);
    226         if (rc == ETIMEDOUT)
    227         {
    228             pSession->resp = GPS_NI_RESPONSE_NORESP;
    229             LOC_LOGD("ni_thread_proc-Thread time out after valting for specified time. Ret Val %d\n",rc );
    230             break;
    231         }
    232     }
    233     LOC_LOGD("ni_thread_proc-Java layer has sent us a user response and return value from "
    234              "pthread_cond_timedwait = %d\n",rc );
    235     pSession->respRecvd = FALSE; /* Reset the user response flag for the next session*/
    236 
    237     LOC_LOGD("pSession->resp is %d\n",pSession->resp);
    238 
    239     // adding this check to support modem restart, in which case, we need the thread
    240     // to exit without calling sending data. We made sure that rawRequest is NULL in
    241     // loc_eng_ni_reset_on_engine_restart()
    242     LocEngAdapter* adapter = pSession->adapter;
    243     LocEngInformNiResponse *msg = NULL;
    244 
    245     if (NULL != pSession->rawRequest) {
    246         if (pSession->resp != GPS_NI_RESPONSE_IGNORE) {
    247             LOC_LOGD("pSession->resp != GPS_NI_RESPONSE_IGNORE \n");
    248             msg = new LocEngInformNiResponse(adapter,
    249                                              pSession->resp,
    250                                              pSession->rawRequest);
    251         } else {
    252             LOC_LOGD("this is the ignore reply for SUPL ES\n");
    253             free(pSession->rawRequest);
    254         }
    255         pSession->rawRequest = NULL;
    256     }
    257     pthread_mutex_unlock(&pSession->tLock);
    258 
    259     pSession->respTimeLeft = 0;
    260     pSession->reqID = 0;
    261 
    262     if (NULL != msg) {
    263         LOC_LOGD("ni_thread_proc: adapter->sendMsg(msg)\n");
    264         adapter->sendMsg(msg);
    265     }
    266 
    267     EXIT_LOG(%s, VOID_RET);
    268     return NULL;
    269 }
    270 
    271 void loc_eng_ni_reset_on_engine_restart(loc_eng_data_s_type &loc_eng_data)
    272 {
    273     ENTRY_LOG();
    274     loc_eng_ni_data_s_type* loc_eng_ni_data_p = &loc_eng_data.loc_eng_ni_data;
    275 
    276     if (NULL == loc_eng_data.ni_notify_cb) {
    277         EXIT_LOG(%s, "loc_eng_ni_init hasn't happened yet.");
    278         return;
    279     }
    280 
    281     // only if modem has requested but then died.
    282     if (NULL != loc_eng_ni_data_p->sessionEs.rawRequest) {
    283         free(loc_eng_ni_data_p->sessionEs.rawRequest);
    284         loc_eng_ni_data_p->sessionEs.rawRequest = NULL;
    285 
    286         pthread_mutex_lock(&loc_eng_ni_data_p->sessionEs.tLock);
    287         // the goal is to wake up ni_thread_proc
    288         // and let it exit.
    289         loc_eng_ni_data_p->sessionEs.respRecvd = TRUE;
    290         pthread_cond_signal(&loc_eng_ni_data_p->sessionEs.tCond);
    291         pthread_mutex_unlock(&loc_eng_ni_data_p->sessionEs.tLock);
    292     }
    293 
    294     if (NULL != loc_eng_ni_data_p->session.rawRequest) {
    295         free(loc_eng_ni_data_p->session.rawRequest);
    296         loc_eng_ni_data_p->session.rawRequest = NULL;
    297 
    298         pthread_mutex_lock(&loc_eng_ni_data_p->session.tLock);
    299         // the goal is to wake up ni_thread_proc
    300         // and let it exit.
    301         loc_eng_ni_data_p->session.respRecvd = TRUE;
    302         pthread_cond_signal(&loc_eng_ni_data_p->session.tCond);
    303         pthread_mutex_unlock(&loc_eng_ni_data_p->session.tLock);
    304     }
    305 
    306     EXIT_LOG(%s, VOID_RET);
    307 }
    308 
    309 /*===========================================================================
    310 FUNCTION    loc_eng_ni_init
    311 
    312 DESCRIPTION
    313    This function initializes the NI interface
    314 
    315 DEPENDENCIES
    316    NONE
    317 
    318 RETURN VALUE
    319    None
    320 
    321 SIDE EFFECTS
    322    N/A
    323 
    324 ===========================================================================*/
    325 void loc_eng_ni_init(loc_eng_data_s_type &loc_eng_data, GpsNiExtCallbacks *callbacks)
    326 {
    327     ENTRY_LOG_CALLFLOW();
    328 
    329     if(callbacks == NULL)
    330         EXIT_LOG(%s, "loc_eng_ni_init: failed, cb is NULL");
    331     else if (NULL == callbacks->notify_cb) {
    332         EXIT_LOG(%s, "loc_eng_ni_init: failed, no cb.");
    333     } else if (NULL != loc_eng_data.ni_notify_cb) {
    334         EXIT_LOG(%s, "loc_eng_ni_init: already inited.");
    335     } else {
    336         loc_eng_ni_data_s_type* loc_eng_ni_data_p = &loc_eng_data.loc_eng_ni_data;
    337         loc_eng_ni_data_p->sessionEs.respTimeLeft = 0;
    338         loc_eng_ni_data_p->sessionEs.respRecvd = FALSE;
    339         loc_eng_ni_data_p->sessionEs.rawRequest = NULL;
    340         loc_eng_ni_data_p->sessionEs.reqID = 0;
    341         pthread_cond_init(&loc_eng_ni_data_p->sessionEs.tCond, NULL);
    342         pthread_mutex_init(&loc_eng_ni_data_p->sessionEs.tLock, NULL);
    343 
    344         loc_eng_ni_data_p->session.respTimeLeft = 0;
    345         loc_eng_ni_data_p->session.respRecvd = FALSE;
    346         loc_eng_ni_data_p->session.rawRequest = NULL;
    347         loc_eng_ni_data_p->session.reqID = 0;
    348         pthread_cond_init(&loc_eng_ni_data_p->session.tCond, NULL);
    349         pthread_mutex_init(&loc_eng_ni_data_p->session.tLock, NULL);
    350 
    351         loc_eng_data.ni_notify_cb = callbacks->notify_cb;
    352         EXIT_LOG(%s, VOID_RET);
    353     }
    354 }
    355 
    356 /*===========================================================================
    357 FUNCTION    loc_eng_ni_respond
    358 
    359 DESCRIPTION
    360    This function receives user response from upper layer framework
    361 
    362 DEPENDENCIES
    363    NONE
    364 
    365 RETURN VALUE
    366    None
    367 
    368 SIDE EFFECTS
    369    N/A
    370 
    371 ===========================================================================*/
    372 void loc_eng_ni_respond(loc_eng_data_s_type &loc_eng_data,
    373                         int notif_id, GpsUserResponseType user_response)
    374 {
    375     ENTRY_LOG_CALLFLOW();
    376     loc_eng_ni_data_s_type* loc_eng_ni_data_p = &loc_eng_data.loc_eng_ni_data;
    377     loc_eng_ni_session_s_type* pSession = NULL;
    378 
    379     if (NULL == loc_eng_data.ni_notify_cb) {
    380         EXIT_LOG(%s, "loc_eng_ni_init hasn't happened yet.");
    381         return;
    382     }
    383 
    384     if (notif_id == loc_eng_ni_data_p->sessionEs.reqID &&
    385         NULL != loc_eng_ni_data_p->sessionEs.rawRequest) {
    386         pSession = &loc_eng_ni_data_p->sessionEs;
    387         // ignore any SUPL NI non-Es session if a SUPL NI ES is accepted
    388         if (user_response == GPS_NI_RESPONSE_ACCEPT &&
    389             NULL != loc_eng_ni_data_p->session.rawRequest) {
    390                 pthread_mutex_lock(&loc_eng_ni_data_p->session.tLock);
    391                 loc_eng_ni_data_p->session.resp = GPS_NI_RESPONSE_IGNORE;
    392                 loc_eng_ni_data_p->session.respRecvd = TRUE;
    393                 pthread_cond_signal(&loc_eng_ni_data_p->session.tCond);
    394                 pthread_mutex_unlock(&loc_eng_ni_data_p->session.tLock);
    395         }
    396     } else if (notif_id == loc_eng_ni_data_p->session.reqID &&
    397         NULL != loc_eng_ni_data_p->session.rawRequest) {
    398         pSession = &loc_eng_ni_data_p->session;
    399     }
    400 
    401     if (pSession) {
    402         LOC_LOGI("loc_eng_ni_respond: send user response %d for notif %d", user_response, notif_id);
    403         pthread_mutex_lock(&pSession->tLock);
    404         pSession->resp = user_response;
    405         pSession->respRecvd = TRUE;
    406         pthread_cond_signal(&pSession->tCond);
    407         pthread_mutex_unlock(&pSession->tLock);
    408     }
    409     else {
    410         LOC_LOGE("loc_eng_ni_respond: notif_id %d not an active session", notif_id);
    411     }
    412 
    413     EXIT_LOG(%s, VOID_RET);
    414 }
    415