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 49using namespace loc_core; 50 51/*============================================================================= 52 * 53 * DATA DECLARATION 54 * 55 *============================================================================*/ 56 57/*============================================================================= 58 * 59 * FUNCTION DECLARATIONS 60 * 61 *============================================================================*/ 62static void* ni_thread_proc(void *args); 63 64struct 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 102FUNCTION loc_eng_ni_request_handler 103 104DESCRIPTION 105 Displays the NI request and awaits user input. If a previous request is 106 in session, it is ignored. 107 108RETURN VALUE 109 none 110 111===========================================================================*/ 112void 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 182FUNCTION ni_thread_proc 183 184===========================================================================*/ 185static 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 246void 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/*=========================================================================== 273FUNCTION loc_eng_ni_init 274 275DESCRIPTION 276 This function initializes the NI interface 277 278DEPENDENCIES 279 NONE 280 281RETURN VALUE 282 None 283 284SIDE EFFECTS 285 N/A 286 287===========================================================================*/ 288void 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/*=========================================================================== 313FUNCTION loc_eng_ni_respond 314 315DESCRIPTION 316 This function receives user response from upper layer framework 317 318DEPENDENCIES 319 NONE 320 321RETURN VALUE 322 None 323 324SIDE EFFECTS 325 N/A 326 327===========================================================================*/ 328void 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