Home | History | Annotate | Download | only in libloc_api
      1 /******************************************************************************
      2   @file:  loc_eng_ni.cpp
      3   @brief:  module for network initiated interactions
      4 
      5   DESCRIPTION
      6      LOC_API network initiated operation support
      7 
      8   INITIALIZATION AND SEQUENCING REQUIREMENTS
      9 
     10   -----------------------------------------------------------------------------
     11   Copyright (c) 2009 QUALCOMM Incorporated.
     12   All Rights Reserved. QUALCOMM Proprietary and Confidential.
     13   -----------------------------------------------------------------------------
     14 ******************************************************************************/
     15 
     16 /*=====================================================================
     17                         EDIT HISTORY FOR MODULE
     18 
     19   This section contains comments describing changes made to the module.
     20   Notice that changes are listed in reverse chronological order.
     21 
     22 when       who      what, where, why
     23 --------   ---      -------------------------------------------------------
     24 07/30/09   dx       Initial version
     25 
     26 $Id:
     27 ======================================================================*/
     28 
     29 #define LOG_NDDEBUG 0
     30 #define LOG_NIDEBUG 0
     31 
     32 #include <stdio.h>
     33 #include <stdlib.h>
     34 #include <pthread.h>
     35 #include <string.h>
     36 #include <ctype.h>
     37 #include <unistd.h>
     38 #include <time.h>
     39 
     40 #include <rpc/rpc.h>
     41 #include <loc_api_rpc_glue.h>
     42 #include <loc_eng.h>
     43 #include <loc_eng_ni.h>
     44 
     45 #define LOG_TAG "lib_locapi"
     46 #include <utils/Log.h>
     47 
     48 // comment this out to enable logging
     49 // #undef LOGD
     50 // #define LOGD(...) {}
     51 
     52 /*=============================================================================
     53  *
     54  *                             DATA DECLARATION
     55  *
     56  *============================================================================*/
     57 
     58 const GpsNiInterface sLocEngNiInterface =
     59 {
     60     sizeof(GpsNiInterface),
     61     loc_eng_ni_init,
     62     loc_eng_ni_respond,
     63 };
     64 
     65 boolean loc_eng_ni_data_init = FALSE;
     66 loc_eng_ni_data_s_type loc_eng_ni_data;
     67 
     68 extern loc_eng_data_s_type loc_eng_data;
     69 
     70 /*=============================================================================
     71  *
     72  *                             FUNCTION DECLARATIONS
     73  *
     74  *============================================================================*/
     75 
     76 /*===========================================================================
     77 
     78 FUNCTION respond_from_enum
     79 
     80 DESCRIPTION
     81    Returns the name of the response
     82 
     83 RETURN VALUE
     84    response name string
     85 
     86 ===========================================================================*/
     87 static const char* respond_from_enum(rpc_loc_ni_user_resp_e_type resp)
     88 {
     89     switch (resp)
     90     {
     91     case RPC_LOC_NI_LCS_NOTIFY_VERIFY_ACCEPT:
     92         return "accept";
     93     case RPC_LOC_NI_LCS_NOTIFY_VERIFY_DENY:
     94         return "deny";
     95     case RPC_LOC_NI_LCS_NOTIFY_VERIFY_NORESP:
     96         return "no response";
     97     default:
     98         return NULL;
     99     }
    100 }
    101 
    102 /*===========================================================================
    103 
    104 FUNCTION loc_ni_respond
    105 
    106 DESCRIPTION
    107    Displays the NI request and awaits user input. If a previous request is
    108    in session, the new one is handled using sys.ni_default_response (if exists);
    109    otherwise, it is denied.
    110 
    111 DEPENDENCY
    112    Do not lock the data by mutex loc_ni_lock
    113 
    114 RETURN VALUE
    115    none
    116 
    117 ===========================================================================*/
    118 static void loc_ni_respond(rpc_loc_ni_user_resp_e_type resp,
    119                     const rpc_loc_ni_event_s_type *request_pass_back
    120 )
    121 {
    122     LOGD("Sending NI response: %s\n", respond_from_enum(resp));
    123 
    124     rpc_loc_ioctl_data_u_type data;
    125     rpc_loc_ioctl_callback_s_type callback_payload;
    126 
    127     memcpy(&data.rpc_loc_ioctl_data_u_type_u.user_verify_resp.ni_event_pass_back,
    128             request_pass_back, sizeof (rpc_loc_ni_event_s_type));
    129     data.rpc_loc_ioctl_data_u_type_u.user_verify_resp.user_resp = resp;
    130 
    131     loc_eng_ioctl(
    132             loc_eng_data.client_handle,
    133             RPC_LOC_IOCTL_INFORM_NI_USER_RESPONSE,
    134             &data,
    135             LOC_IOCTL_DEFAULT_TIMEOUT,
    136             &callback_payload
    137     );
    138 }
    139 
    140 /*===========================================================================
    141 
    142 FUNCTION loc_ni_fill_notif_verify_type
    143 
    144 DESCRIPTION
    145    Fills need_notify, need_verify, etc.
    146 
    147 RETURN VALUE
    148    none
    149 
    150 ===========================================================================*/
    151 static boolean loc_ni_fill_notif_verify_type(GpsNiNotification *notif,
    152       rpc_loc_ni_notify_verify_e_type notif_priv)
    153 {
    154     notif->notify_flags       = 0;
    155     notif->default_response   = GPS_NI_RESPONSE_NORESP;
    156 
    157     switch (notif_priv)
    158     {
    159     case RPC_LOC_NI_USER_NO_NOTIFY_NO_VERIFY:
    160         notif->notify_flags = 0;
    161         break;
    162 
    163     case RPC_LOC_NI_USER_NOTIFY_ONLY:
    164         notif->notify_flags = GPS_NI_NEED_NOTIFY;
    165         break;
    166 
    167     case RPC_LOC_NI_USER_NOTIFY_VERIFY_ALLOW_NO_RESP:
    168         notif->notify_flags = GPS_NI_NEED_NOTIFY | GPS_NI_NEED_VERIFY;
    169         notif->default_response = GPS_NI_RESPONSE_ACCEPT;
    170         break;
    171 
    172     case RPC_LOC_NI_USER_NOTIFY_VERIFY_NOT_ALLOW_NO_RESP:
    173         notif->notify_flags = GPS_NI_NEED_NOTIFY | GPS_NI_NEED_VERIFY;
    174         notif->default_response = GPS_NI_RESPONSE_DENY;
    175         break;
    176 
    177     case RPC_LOC_NI_USER_PRIVACY_OVERRIDE:
    178         notif->notify_flags = GPS_NI_PRIVACY_OVERRIDE;
    179         break;
    180 
    181     default:
    182         return FALSE;
    183     }
    184 
    185     return TRUE;
    186 }
    187 
    188 /*===========================================================================
    189 
    190 FUNCTION hexcode
    191 
    192 DESCRIPTION
    193    Converts a binary array into a Hex string. E.g., 1F 00 3F --> "1F003F"
    194 
    195 RETURN VALUE
    196    bytes encoded
    197 
    198 ===========================================================================*/
    199 static int hexcode(char *hexstring, int string_size, const char *data, int data_size)
    200 {
    201     int i;
    202     for (i = 0; i < data_size; i++)
    203     {
    204         char ch = data[i];
    205         if (i*2 + 3 <= string_size)
    206         {
    207             snprintf(&hexstring[i*2], 3, "%02X", ch);
    208         }
    209         else {
    210             break;
    211         }
    212     }
    213     return i;
    214 }
    215 
    216 static GpsNiEncodingType convert_encoding_type(int loc_encoding)
    217 {
    218     GpsNiEncodingType enc = GPS_ENC_UNKNOWN;
    219 
    220     switch (loc_encoding)
    221     {
    222     case RPC_LOC_NI_SUPL_UTF8:
    223         enc = GPS_ENC_SUPL_UTF8;
    224         break;
    225     case RPC_LOC_NI_SUPL_UCS2:
    226         enc = GPS_ENC_SUPL_UCS2;
    227         break;
    228     case RPC_LOC_NI_SUPL_GSM_DEFAULT:
    229         enc = GPS_ENC_SUPL_GSM_DEFAULT;
    230         break;
    231     default:
    232         break;
    233     }
    234 
    235     return enc;
    236 }
    237 
    238 /*===========================================================================
    239 
    240 FUNCTION loc_ni_request_handler
    241 
    242 DESCRIPTION
    243    Displays the NI request and awaits user input. If a previous request is
    244    in session, it is ignored.
    245 
    246 RETURN VALUE
    247    none
    248 
    249 ===========================================================================*/
    250 static void loc_ni_request_handler(const char *msg, const rpc_loc_ni_event_s_type *ni_req)
    251 {
    252     GpsNiNotification notif;
    253     notif.size = sizeof(notif);
    254     strlcpy(notif.text, "[text]", sizeof notif.text);    // defaults
    255     strlcpy(notif.requestor_id, "[requestor id]", sizeof notif.requestor_id);
    256 
    257     /* If busy, use default or deny */
    258     if (loc_eng_ni_data.notif_in_progress)
    259     {
    260 #if 0
    261         /* Cannot be here because the current thread is in RPC client */
    262         /* XXX Consider adding an event queue to process overlapped NI requests */
    263         loc_ni_user_resp_e_type response =
    264             sys.ni_default_resp == 1 /* accept */ ?
    265                     LOC_NI_LCS_NOTIFY_VERIFY_ACCEPT :
    266                     LOC_NI_LCS_NOTIFY_VERIFY_DENY;
    267 
    268         loc_ni_respond(response, ni_req); */
    269 #endif
    270         LOGW("loc_ni_request_handler, notification in progress, new NI request ignored, type: %d",
    271                 ni_req->event);
    272     }
    273     else {
    274         /* Print notification */
    275         LOGD("NI Notification: %s, event: %d", msg, ni_req->event);
    276 
    277         pthread_mutex_lock(&loc_eng_ni_data.loc_ni_lock);
    278 
    279         /* Save request */
    280         memcpy(&loc_eng_ni_data.loc_ni_request, ni_req, sizeof loc_eng_ni_data.loc_ni_request);
    281 
    282         /* Set up NI response waiting */
    283         loc_eng_ni_data.notif_in_progress = TRUE;
    284         loc_eng_ni_data.current_notif_id = abs(rand());
    285 
    286         /* Fill in notification */
    287         notif.notification_id = loc_eng_ni_data.current_notif_id;
    288 
    289         const rpc_loc_ni_vx_notify_verify_req_s_type *vx_req;
    290         const rpc_loc_ni_supl_notify_verify_req_s_type *supl_req;
    291         const rpc_loc_ni_umts_cp_notify_verify_req_s_type *umts_cp_req;
    292 
    293         switch (ni_req->event)
    294         {
    295             case RPC_LOC_NI_EVENT_VX_NOTIFY_VERIFY_REQ:
    296                 vx_req = &ni_req->payload.rpc_loc_ni_event_payload_u_type_u.vx_req;
    297                 notif.ni_type     = GPS_NI_TYPE_VOICE;
    298                 notif.timeout     = LOC_NI_NO_RESPONSE_TIME; // vx_req->user_resp_timer_val;
    299                 memset(notif.extras, 0, sizeof notif.extras);
    300                 memset(notif.text, 0, sizeof notif.text);
    301                 memset(notif.requestor_id, 0, sizeof notif.requestor_id);
    302 
    303                 // Requestor ID
    304                 hexcode(notif.requestor_id, sizeof notif.requestor_id,
    305                         vx_req->requester_id.requester_id,
    306                         vx_req->requester_id.requester_id_length);
    307 
    308                 notif.text_encoding = 0; // No text and no encoding
    309                 notif.requestor_id_encoding = convert_encoding_type(vx_req->encoding_scheme);
    310 
    311                 // Set default_response & notify_flags
    312                 loc_ni_fill_notif_verify_type(&notif, vx_req->notification_priv_type);
    313 
    314                 break;
    315 
    316             case RPC_LOC_NI_EVENT_UMTS_CP_NOTIFY_VERIFY_REQ:
    317                 umts_cp_req = &ni_req->payload.rpc_loc_ni_event_payload_u_type_u.umts_cp_req;
    318                 notif.ni_type     = GPS_NI_TYPE_UMTS_CTRL_PLANE;
    319                 notif.timeout     = LOC_NI_NO_RESPONSE_TIME; // umts_cp_req->user_response_timer;
    320                 memset(notif.extras, 0, sizeof notif.extras);
    321                 memset(notif.text, 0, sizeof notif.text);
    322                 memset(notif.requestor_id, 0, sizeof notif.requestor_id);
    323 
    324                 // Stores notification text
    325                 hexcode(notif.text, sizeof notif.text,
    326 #if (AMSS_VERSION==3200)
    327                         umts_cp_req->notification_text.notification_text_val,
    328 #else
    329                         umts_cp_req->notification_text,
    330 #endif
    331                         umts_cp_req->notification_length);
    332 
    333                 // Stores requestor ID
    334                 hexcode(notif.requestor_id, sizeof notif.requestor_id,
    335 #if (AMSS_VERSION==3200)
    336                         umts_cp_req->requestor_id.requestor_id_string.requestor_id_string_val,
    337 #else
    338                         umts_cp_req->requestor_id.requestor_id_string,
    339 #endif
    340                         umts_cp_req->requestor_id.string_len);
    341 
    342                 notif.text_encoding = convert_encoding_type(umts_cp_req->datacoding_scheme);
    343                 notif.requestor_id_encoding = convert_encoding_type(umts_cp_req->datacoding_scheme);
    344 
    345                 // Set default_response & notify_flags
    346                 loc_ni_fill_notif_verify_type(&notif, umts_cp_req->notification_priv_type);
    347 
    348                 break;
    349 
    350             case RPC_LOC_NI_EVENT_SUPL_NOTIFY_VERIFY_REQ:
    351                 supl_req = &ni_req->payload.rpc_loc_ni_event_payload_u_type_u.supl_req;
    352                 notif.ni_type     = GPS_NI_TYPE_UMTS_SUPL;
    353                 notif.timeout     = LOC_NI_NO_RESPONSE_TIME; // supl_req->user_response_timer;
    354                 memset(notif.extras, 0, sizeof notif.extras);
    355                 memset(notif.text, 0, sizeof notif.text);
    356                 memset(notif.requestor_id, 0, sizeof notif.requestor_id);
    357 
    358                 // Client name
    359                 if (supl_req->flags & RPC_LOC_NI_CLIENT_NAME_PRESENT)
    360                 {
    361                     hexcode(notif.text, sizeof notif.text,
    362 #if (AMSS_VERSION==3200)
    363                             supl_req->client_name.client_name_string.client_name_string_val,   /* buffer */
    364 #else
    365                             supl_req->client_name.client_name_string,                          /* buffer */
    366 #endif
    367                             supl_req->client_name.string_len                                   /* length */
    368                     );
    369                     LOGD("SUPL NI: client_name: %s len=%d", notif.text, supl_req->client_name.string_len);
    370                 } else {
    371                     LOGD("SUPL NI: client_name not present.");
    372                 }
    373 
    374                 // Requestor ID
    375                 if (supl_req->flags & RPC_LOC_NI_REQUESTOR_ID_PRESENT)
    376                 {
    377                     hexcode(notif.requestor_id, sizeof notif.requestor_id,
    378 #if (AMSS_VERSION==3200)
    379                             supl_req->requestor_id.requestor_id_string.requestor_id_string_val,  /* buffer */
    380 #else
    381                             supl_req->requestor_id.requestor_id_string,                          /* buffer */
    382 #endif
    383                             supl_req->requestor_id.string_len                                    /* length */
    384                     );
    385                     LOGD("SUPL NI: requestor_id: %s len=%d", notif.requestor_id, supl_req->requestor_id.string_len);
    386                 } else {
    387                     LOGD("SUPL NI: requestor_id not present.");
    388                 }
    389 
    390                 // Encoding type
    391                 if (supl_req->flags & RPC_LOC_NI_ENCODING_TYPE_PRESENT)
    392                 {
    393                     notif.text_encoding = convert_encoding_type(supl_req->datacoding_scheme);
    394                     notif.requestor_id_encoding = convert_encoding_type(supl_req->datacoding_scheme);
    395                 } else {
    396                     notif.text_encoding = notif.requestor_id_encoding = GPS_ENC_UNKNOWN;
    397                 }
    398 
    399                 // Set default_response & notify_flags
    400                 loc_ni_fill_notif_verify_type(&notif, ni_req->payload.rpc_loc_ni_event_payload_u_type_u.supl_req.notification_priv_type);
    401 
    402                 break;
    403 
    404             default:
    405                 LOGE("loc_ni_request_handler, unknown request event: %d", ni_req->event);
    406                 return;
    407         }
    408 
    409         /* Log requestor ID and text for debugging */
    410         LOGI("Notification: notif_type: %d, timeout: %d, default_resp: %d", notif.ni_type, notif.timeout, notif.default_response);
    411         LOGI("              requestor_id: %s (encoding: %d)", notif.requestor_id, notif.requestor_id_encoding);
    412         LOGI("              text: %s text (encoding: %d)", notif.text, notif.text_encoding);
    413 
    414         /* For robustness, always sets a timeout to clear up the notification status, even though
    415         * the OEM layer in java does not do so.
    416         **/
    417         loc_eng_ni_data.response_time_left = 5 + (notif.timeout != 0 ? notif.timeout : LOC_NI_NO_RESPONSE_TIME);
    418         LOGI("Automatically sends 'no response' in %d seconds (to clear status)\n", loc_eng_ni_data.response_time_left);
    419 
    420         pthread_mutex_unlock(&loc_eng_ni_data.loc_ni_lock);
    421 
    422         /* Notify callback */
    423         if (loc_eng_data.ni_notify_cb != NULL)
    424         {
    425             loc_eng_data.ni_notify_cb(&notif);
    426         }
    427     }
    428 }
    429 
    430 /*===========================================================================
    431 
    432 FUNCTION loc_ni_process_user_response
    433 
    434 DESCRIPTION
    435    Handles user input from the UI
    436 
    437 RETURN VALUE
    438    error code (0 for successful, -1 for error)
    439 
    440 ===========================================================================*/
    441 int loc_ni_process_user_response(GpsUserResponseType userResponse)
    442 {
    443     LOGD("NI response from UI: %d", userResponse);
    444 
    445     rpc_loc_ni_user_resp_e_type resp;
    446     switch (userResponse)
    447     {
    448         case GPS_NI_RESPONSE_ACCEPT:
    449             resp = RPC_LOC_NI_LCS_NOTIFY_VERIFY_ACCEPT;
    450             break;
    451         case GPS_NI_RESPONSE_DENY:
    452             resp = RPC_LOC_NI_LCS_NOTIFY_VERIFY_DENY;
    453             break;
    454         case GPS_NI_RESPONSE_NORESP:
    455             resp = RPC_LOC_NI_LCS_NOTIFY_VERIFY_NORESP;
    456             break;
    457         default:
    458             return -1;
    459     }
    460 
    461     loc_ni_respond(resp, &loc_eng_ni_data.loc_ni_request);
    462 
    463     /* Make the NI respond */
    464     pthread_mutex_lock(&loc_eng_ni_data.loc_ni_lock);
    465     loc_eng_ni_data.notif_in_progress = FALSE;
    466     loc_eng_ni_data.response_time_left = 0;
    467     loc_eng_ni_data.current_notif_id = -1;
    468     pthread_mutex_unlock(&loc_eng_ni_data.loc_ni_lock);
    469 
    470     return 0;
    471 }
    472 
    473 /*===========================================================================
    474 
    475 FUNCTION loc_eng_ni_callback
    476 
    477 DESCRIPTION
    478    Loc API callback handler
    479 
    480 RETURN VALUE
    481    error code (0 for success)
    482 
    483 ===========================================================================*/
    484 int loc_eng_ni_callback (
    485       rpc_loc_event_mask_type               loc_event,              /* event mask           */
    486       const rpc_loc_event_payload_u_type*   loc_event_payload       /* payload              */
    487 )
    488 {
    489     int rc = 0;
    490     const rpc_loc_ni_event_s_type *ni_req = &loc_event_payload->rpc_loc_event_payload_u_type_u.ni_request;
    491     if (loc_event == RPC_LOC_EVENT_NI_NOTIFY_VERIFY_REQUEST)
    492     {
    493         switch (ni_req->event)
    494         {
    495             case RPC_LOC_NI_EVENT_VX_NOTIFY_VERIFY_REQ:
    496                 LOGI("VX Notification");
    497                 loc_ni_request_handler("VX Notify", ni_req);
    498                 break;
    499 
    500             case RPC_LOC_NI_EVENT_UMTS_CP_NOTIFY_VERIFY_REQ:
    501                 LOGI("UMTS CP Notification\n");
    502                 loc_ni_request_handler("UMTS CP Notify", ni_req);
    503                 break;
    504 
    505             case RPC_LOC_NI_EVENT_SUPL_NOTIFY_VERIFY_REQ:
    506                 LOGI("SUPL Notification\n");
    507                 loc_ni_request_handler("SUPL Notify", ni_req);
    508                 break;
    509 
    510             default:
    511                 LOGE("Unknown NI event: %x\n", (int) ni_req->event);
    512                 break;
    513         }
    514     }
    515     return rc;
    516 }
    517 
    518 /*===========================================================================
    519 
    520 FUNCTION loc_ni_thread_proc
    521 
    522 ===========================================================================*/
    523 static void loc_ni_thread_proc(void *unused)
    524 {
    525     LOGI("Starting Loc NI thread...\n");
    526 
    527     while (1)
    528     {
    529         /* wakes up every second to check timed out requests */
    530         sleep(1);
    531 
    532         pthread_mutex_lock(&loc_eng_ni_data.loc_ni_lock);
    533 
    534         if (loc_eng_ni_data.notif_in_progress && loc_eng_ni_data.response_time_left > 0)
    535         {
    536             loc_eng_ni_data.response_time_left--;
    537             if (loc_eng_ni_data.response_time_left <= 0)
    538             {
    539                 loc_ni_respond(RPC_LOC_NI_LCS_NOTIFY_VERIFY_NORESP, &loc_eng_ni_data.loc_ni_request);
    540                 loc_eng_ni_data.notif_in_progress = FALSE;
    541             }
    542         }
    543 
    544         pthread_mutex_unlock(&loc_eng_ni_data.loc_ni_lock);
    545     } /* while (1) */
    546 }
    547 
    548 /*===========================================================================
    549 FUNCTION    loc_eng_ni_init
    550 
    551 DESCRIPTION
    552    This function initializes the NI interface
    553 
    554 DEPENDENCIES
    555    NONE
    556 
    557 RETURN VALUE
    558    None
    559 
    560 SIDE EFFECTS
    561    N/A
    562 
    563 ===========================================================================*/
    564 void loc_eng_ni_init(GpsNiCallbacks *callbacks)
    565 {
    566     LOGD("loc_eng_ni_init: entered.");
    567 
    568     if (!loc_eng_ni_data_init)
    569     {
    570         pthread_mutex_init(&loc_eng_ni_data.loc_ni_lock, NULL);
    571         callbacks->create_thread_cb("loc_api_ni", loc_ni_thread_proc, NULL);
    572         loc_eng_ni_data_init = TRUE;
    573     }
    574 
    575     loc_eng_ni_data.notif_in_progress = FALSE;
    576     loc_eng_ni_data.current_notif_id = -1;
    577     loc_eng_ni_data.response_time_left = 0;
    578 
    579     srand(time(NULL));
    580     loc_eng_data.ni_notify_cb = callbacks->notify_cb;
    581 }
    582 
    583 /*===========================================================================
    584 FUNCTION    loc_eng_ni_respond
    585 
    586 DESCRIPTION
    587    This function sends an NI respond to the modem processor
    588 
    589 DEPENDENCIES
    590    NONE
    591 
    592 RETURN VALUE
    593    None
    594 
    595 SIDE EFFECTS
    596    N/A
    597 
    598 ===========================================================================*/
    599 void loc_eng_ni_respond(int notif_id, GpsUserResponseType user_response)
    600 {
    601     if (notif_id == loc_eng_ni_data.current_notif_id && loc_eng_ni_data.notif_in_progress)
    602     {
    603         LOGI("loc_eng_ni_respond: send user response %d for notif %d", user_response, notif_id);
    604         loc_ni_process_user_response(user_response);
    605     } else {
    606         LOGE("loc_eng_ni_respond: notif_id %d mismatch or notification not in progress, response: %d",
    607             notif_id, user_response);
    608     }
    609 }
    610