Home | History | Annotate | Download | only in libloc_api_50001
      1 /* Copyright (c) 2009-2013, 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 
    120     if (NULL == loc_eng_data.ni_notify_cb) {
    121         EXIT_LOG(%s, "loc_eng_ni_init hasn't happened yet.");
    122         return;
    123     }
    124 
    125     /* If busy, use default or deny */
    126     if (NULL != loc_eng_ni_data_p->rawRequest)
    127     {
    128         /* XXX Consider sending a NO RESPONSE reply or queue the request */
    129         LOC_LOGW("loc_eng_ni_request_handler, notification in progress, new NI request ignored, type: %d",
    130                  notif->ni_type);
    131         if (NULL != passThrough) {
    132             free((void*)passThrough);
    133         }
    134     }
    135     else {
    136         /* Save request */
    137         loc_eng_ni_data_p->rawRequest = (void*)passThrough;
    138 
    139         /* Fill in notification */
    140         ((GpsNiNotification*)notif)->notification_id = loc_eng_ni_data_p->reqID;
    141 
    142         if (notif->notify_flags == GPS_NI_PRIVACY_OVERRIDE)
    143         {
    144             loc_eng_mute_one_session(loc_eng_data);
    145         }
    146 
    147         /* Log requestor ID and text for debugging */
    148         LOC_LOGI("Notification: notif_type: %d, timeout: %d, default_resp: %d", notif->ni_type, notif->timeout, notif->default_response);
    149         LOC_LOGI("              requestor_id: %s (encoding: %d)", notif->requestor_id, notif->requestor_id_encoding);
    150         LOC_LOGI("              text: %s text (encoding: %d)", notif->text, notif->text_encoding);
    151         if (notif->extras[0])
    152         {
    153             LOC_LOGI("              extras: %s", notif->extras);
    154         }
    155 
    156         /* For robustness, spawn a thread at this point to timeout to clear up the notification status, even though
    157          * the OEM layer in java does not do so.
    158          **/
    159         loc_eng_ni_data_p->respTimeLeft = 5 + (notif->timeout != 0 ? notif->timeout : LOC_NI_NO_RESPONSE_TIME);
    160         LOC_LOGI("Automatically sends 'no response' in %d seconds (to clear status)\n", loc_eng_ni_data_p->respTimeLeft);
    161 
    162         int rc = 0;
    163         rc = pthread_create(&loc_eng_ni_data_p->thread, NULL, ni_thread_proc, &loc_eng_data);
    164         if (rc)
    165         {
    166             LOC_LOGE("Loc NI thread is not created.\n");
    167         }
    168         rc = pthread_detach(loc_eng_ni_data_p->thread);
    169         if (rc)
    170         {
    171             LOC_LOGE("Loc NI thread is not detached.\n");
    172         }
    173 
    174         CALLBACK_LOG_CALLFLOW("ni_notify_cb - id", %d, notif->notification_id);
    175         loc_eng_data.ni_notify_cb((GpsNiNotification*)notif);
    176     }
    177     EXIT_LOG(%s, VOID_RET);
    178 }
    179 
    180 /*===========================================================================
    181 
    182 FUNCTION ni_thread_proc
    183 
    184 ===========================================================================*/
    185 static void* ni_thread_proc(void *args)
    186 {
    187     ENTRY_LOG();
    188 
    189     loc_eng_data_s_type* loc_eng_data_p = (loc_eng_data_s_type*)args;
    190     loc_eng_ni_data_s_type* loc_eng_ni_data_p = &loc_eng_data_p->loc_eng_ni_data;
    191     int rc = 0;          /* return code from pthread calls */
    192 
    193     struct timeval present_time;
    194     struct timespec expire_time;
    195 
    196     LOC_LOGD("Starting Loc NI thread...\n");
    197     pthread_mutex_lock(&loc_eng_ni_data_p->tLock);
    198     /* Calculate absolute expire time */
    199     gettimeofday(&present_time, NULL);
    200     expire_time.tv_sec  = present_time.tv_sec + loc_eng_ni_data_p->respTimeLeft;
    201     expire_time.tv_nsec = present_time.tv_usec * 1000;
    202     LOC_LOGD("ni_thread_proc-Time out set for abs time %ld with delay %d sec\n",
    203              (long) expire_time.tv_sec, loc_eng_ni_data_p->respTimeLeft );
    204 
    205     while (!loc_eng_ni_data_p->respRecvd)
    206     {
    207         rc = pthread_cond_timedwait(&loc_eng_ni_data_p->tCond,
    208                                     &loc_eng_ni_data_p->tLock,
    209                                     &expire_time);
    210         if (rc == ETIMEDOUT)
    211         {
    212             loc_eng_ni_data_p->resp = GPS_NI_RESPONSE_NORESP;
    213             LOC_LOGD("ni_thread_proc-Thread time out after valting for specified time. Ret Val %d\n",rc );
    214             break;
    215         }
    216     }
    217     LOC_LOGD("ni_thread_proc-Java layer has sent us a user response and return value from "
    218              "pthread_cond_timedwait = %d\n",rc );
    219     loc_eng_ni_data_p->respRecvd = FALSE; /* Reset the user response flag for the next session*/
    220 
    221     // adding this check to support modem restart, in which case, we need the thread
    222     // to exit without calling sending data. We made sure that rawRequest is NULL in
    223     // loc_eng_ni_reset_on_engine_restart()
    224     LocEngAdapter* adapter = loc_eng_data_p->adapter;
    225     LocEngInformNiResponse *msg = NULL;
    226 
    227     if (NULL != loc_eng_ni_data_p->rawRequest) {
    228         msg = new LocEngInformNiResponse(adapter,
    229                                          loc_eng_ni_data_p->resp,
    230                                          loc_eng_ni_data_p->rawRequest);
    231         loc_eng_ni_data_p->rawRequest = NULL;
    232     }
    233     pthread_mutex_unlock(&loc_eng_ni_data_p->tLock);
    234 
    235     loc_eng_ni_data_p->respTimeLeft = 0;
    236     loc_eng_ni_data_p->reqID++;
    237 
    238     if (NULL != msg) {
    239         adapter->sendMsg(msg);
    240     }
    241 
    242     EXIT_LOG(%s, VOID_RET);
    243     return NULL;
    244 }
    245 
    246 void loc_eng_ni_reset_on_engine_restart(loc_eng_data_s_type &loc_eng_data)
    247 {
    248     ENTRY_LOG();
    249     loc_eng_ni_data_s_type* loc_eng_ni_data_p = &loc_eng_data.loc_eng_ni_data;
    250 
    251     if (NULL == loc_eng_data.ni_notify_cb) {
    252         EXIT_LOG(%s, "loc_eng_ni_init hasn't happened yet.");
    253         return;
    254     }
    255 
    256     // only if modem has requested but then died.
    257     if (NULL != loc_eng_ni_data_p->rawRequest) {
    258         free(loc_eng_ni_data_p->rawRequest);
    259         loc_eng_ni_data_p->rawRequest = NULL;
    260 
    261         pthread_mutex_lock(&loc_eng_ni_data_p->tLock);
    262         // the goal is to wake up ni_thread_proc
    263         // and let it exit.
    264         loc_eng_ni_data_p->respRecvd = TRUE;
    265         pthread_cond_signal(&loc_eng_ni_data_p->tCond);
    266         pthread_mutex_unlock(&loc_eng_ni_data_p->tLock);
    267     }
    268 
    269     EXIT_LOG(%s, VOID_RET);
    270 }
    271 
    272 /*===========================================================================
    273 FUNCTION    loc_eng_ni_init
    274 
    275 DESCRIPTION
    276    This function initializes the NI interface
    277 
    278 DEPENDENCIES
    279    NONE
    280 
    281 RETURN VALUE
    282    None
    283 
    284 SIDE EFFECTS
    285    N/A
    286 
    287 ===========================================================================*/
    288 void loc_eng_ni_init(loc_eng_data_s_type &loc_eng_data, GpsNiExtCallbacks *callbacks)
    289 {
    290     ENTRY_LOG_CALLFLOW();
    291 
    292     if(callbacks == NULL)
    293         EXIT_LOG(%s, "loc_eng_ni_init: failed, cb is NULL");
    294     else if (NULL == callbacks->notify_cb) {
    295         EXIT_LOG(%s, "loc_eng_ni_init: failed, no cb.");
    296     } else if (NULL != loc_eng_data.ni_notify_cb) {
    297         EXIT_LOG(%s, "loc_eng_ni_init: already inited.");
    298     } else {
    299         loc_eng_ni_data_s_type* loc_eng_ni_data_p = &loc_eng_data.loc_eng_ni_data;
    300         loc_eng_ni_data_p->respTimeLeft = 0;
    301         loc_eng_ni_data_p->respRecvd = FALSE;
    302         loc_eng_ni_data_p->rawRequest = NULL;
    303         loc_eng_ni_data_p->reqID = 0;
    304         pthread_cond_init(&loc_eng_ni_data_p->tCond, NULL);
    305         pthread_mutex_init(&loc_eng_ni_data_p->tLock, NULL);
    306 
    307         loc_eng_data.ni_notify_cb = callbacks->notify_cb;
    308         EXIT_LOG(%s, VOID_RET);
    309     }
    310 }
    311 
    312 /*===========================================================================
    313 FUNCTION    loc_eng_ni_respond
    314 
    315 DESCRIPTION
    316    This function receives user response from upper layer framework
    317 
    318 DEPENDENCIES
    319    NONE
    320 
    321 RETURN VALUE
    322    None
    323 
    324 SIDE EFFECTS
    325    N/A
    326 
    327 ===========================================================================*/
    328 void loc_eng_ni_respond(loc_eng_data_s_type &loc_eng_data,
    329                         int notif_id, GpsUserResponseType user_response)
    330 {
    331     ENTRY_LOG_CALLFLOW();
    332     loc_eng_ni_data_s_type* loc_eng_ni_data_p = &loc_eng_data.loc_eng_ni_data;
    333 
    334     if (NULL == loc_eng_data.ni_notify_cb) {
    335         EXIT_LOG(%s, "loc_eng_ni_init hasn't happened yet.");
    336         return;
    337     }
    338 
    339     if (notif_id == loc_eng_ni_data_p->reqID &&
    340         NULL != loc_eng_ni_data_p->rawRequest)
    341     {
    342         LOC_LOGI("loc_eng_ni_respond: send user response %d for notif %d", user_response, notif_id);
    343         pthread_mutex_lock(&loc_eng_ni_data_p->tLock);
    344         loc_eng_ni_data_p->resp = user_response;
    345         loc_eng_ni_data_p->respRecvd = TRUE;
    346         pthread_cond_signal(&loc_eng_ni_data_p->tCond);
    347         pthread_mutex_unlock(&loc_eng_ni_data_p->tLock);
    348     }
    349     else {
    350         LOC_LOGE("loc_eng_ni_respond: reqID %d and notif_id %d mismatch or rawRequest %p, response: %d",
    351                  loc_eng_ni_data_p->reqID, notif_id, loc_eng_ni_data_p->rawRequest, user_response);
    352     }
    353 
    354     EXIT_LOG(%s, VOID_RET);
    355 }
    356