Home | History | Annotate | Download | only in cpp
      1 /**
      2  * Copyright (C) 2010 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #include <map>
     18 
     19 #include <v8.h>
     20 #include <telephony/ril.h>
     21 
     22 
     23 #include "ril.pb.h"
     24 
     25 #include "logging.h"
     26 #include "js_support.h"
     27 #include "mock_ril.h"
     28 #include "node_buffer.h"
     29 #include "node_object_wrap.h"
     30 #include "node_util.h"
     31 #include "protobuf_v8.h"
     32 #include "status.h"
     33 #include "util.h"
     34 #include "worker.h"
     35 
     36 #include "requests.h"
     37 
     38 //#define REQUESTS_DEBUG
     39 #ifdef  REQUESTS_DEBUG
     40 
     41 #define DBG(...) LOGD(__VA_ARGS__)
     42 
     43 #else
     44 
     45 #define DBG(...)
     46 
     47 #endif
     48 
     49 
     50 /**
     51  * Request has no data so create an empty Buffer
     52  */
     53 int ReqWithNoData(Buffer **pBuffer,
     54         const void *data, const size_t datalen, const RIL_Token t) {
     55     int status;
     56     static Buffer *emptyBuffer = Buffer::New(0L);
     57 
     58     DBG("ReqWithNoData E");
     59     *pBuffer = emptyBuffer;
     60     status = STATUS_OK;
     61 
     62     DBG("ReqWithNoData X status=%d", status);
     63     return status;
     64 }
     65 
     66 /**
     67  * request for RIL_REQUEST_ENTER_SIM_PIN  // 2
     68  */
     69 int ReqEnterSimPin(Buffer **pBuffer,
     70         const void *data, const size_t datalen, const RIL_Token t) {
     71     int status;
     72     Buffer *buffer;
     73 
     74     DBG("ReqEnterSimPin E");
     75     if (datalen < sizeof(int)) {
     76         LOGE("ReqEnterSimPin: data to small err size < sizeof int");
     77         status = STATUS_BAD_DATA;
     78     } else {
     79         ril_proto::ReqEnterSimPin *req = new ril_proto::ReqEnterSimPin();
     80         DBG("ReqEnterSimPin: pin = %s", ((const char **)data)[0]);
     81         req->set_pin((((char **)data)[0]));
     82         buffer = Buffer::New(req->ByteSize());
     83         req->SerializeToArray(buffer->data(), buffer->length());
     84         delete req;
     85         *pBuffer = buffer;
     86         status = STATUS_OK;
     87     }
     88     DBG("ReqEnterSimPin X status=%d", status);
     89     return status;
     90 }
     91 
     92 /**
     93  * request for RIL_REQUEST_DIAL  // 10
     94  */
     95 int ReqDial(Buffer **pBuffer,
     96             const void *data, const size_t datalen, const RIL_Token t) {
     97     int status;
     98     Buffer *buffer;
     99 
    100     DBG("ReqDial E");
    101     DBG("data=%p datalen=%d t=%p", data, datalen, t);
    102 
    103     if (datalen < sizeof(int)) {
    104         LOGE("ReqDial: data to small err size < sizeof int");
    105         status = STATUS_BAD_DATA;
    106     } else {
    107         ril_proto::ReqDial *req = new ril_proto::ReqDial();
    108 
    109         // cast the data to RIL_Dial
    110         RIL_Dial *rilDial = (RIL_Dial *)data;
    111         DBG("ReqDial: rilDial->address =%s, rilDial->clir=%d", rilDial->address, rilDial->clir);
    112 
    113         req->set_address(rilDial->address);
    114         req->set_clir(rilDial->clir);
    115         ril_proto::RilUusInfo *uusInfo = (ril_proto::RilUusInfo *)(&(req->uus_info()));
    116 
    117         if (rilDial->uusInfo != NULL) {
    118             DBG("ReqDial: print uusInfo:");
    119             DBG("rilDial->uusInfo->uusType = %d, "
    120                 "rilDial->uusInfo->uusDcs =%d, "
    121                 "rilDial->uusInfo->uusLength=%d, "
    122                 "rilDial->uusInfo->uusData = %s",
    123                 rilDial->uusInfo->uusType,
    124                 rilDial->uusInfo->uusDcs,
    125                 rilDial->uusInfo->uusLength,
    126                 rilDial->uusInfo->uusData);
    127 
    128             uusInfo->set_uus_type((ril_proto::RilUusType)rilDial->uusInfo->uusType);
    129             uusInfo->set_uus_dcs((ril_proto::RilUusDcs)rilDial->uusInfo->uusDcs);
    130             uusInfo->set_uus_length(rilDial->uusInfo->uusLength);
    131             uusInfo->set_uus_data(rilDial->uusInfo->uusData);
    132         } else {
    133             DBG("uusInfo is NULL");
    134         }
    135 
    136         DBG("ReqDial: after set the request");
    137         DBG("req->ByetSize=%d", req->ByteSize());
    138         buffer = Buffer::New(req->ByteSize());
    139         DBG("buffer size=%d", buffer->length());
    140 
    141         req->SerializeToArray(buffer->data(), buffer->length());
    142         delete req;
    143         *pBuffer = buffer;
    144         status = STATUS_OK;
    145         DBG("ReqDial X, buffer->length()=%d", buffer->length());
    146     }
    147     DBG("ReqDial X status = %d", status);
    148     return status;
    149 }
    150 
    151 /**
    152  * request for RIL_REQUEST_HANGUP    // 12
    153  */
    154 int ReqHangUp(Buffer **pBuffer,
    155         const void *data, const size_t datalen, const RIL_Token t) {
    156     int status;
    157     Buffer *buffer;
    158 
    159     DBG("ReqHangUp E");
    160     if (datalen < sizeof(int)) {
    161         LOGE("ReqHangUp: data to small err size < sizeof int");
    162         status = STATUS_BAD_DATA;
    163     } else {
    164         ril_proto::ReqHangUp *req = new ril_proto::ReqHangUp();
    165         DBG("ReqHangUp: connection_index=%d", ((int *)data)[0]);
    166         req->set_connection_index(((int *)data)[0]);
    167         buffer = Buffer::New(req->ByteSize());
    168         req->SerializeToArray(buffer->data(), buffer->length());
    169         delete req;
    170         *pBuffer = buffer;
    171         status = STATUS_OK;
    172     }
    173     DBG("ReqHangUp X status=%d", status);
    174     return status;
    175 }
    176 
    177 /**
    178  * request for RIL_REQUEST_SEPARATE_CONNECTION    // 52
    179  */
    180 int ReqSeparateConnection (Buffer **pBuffer,
    181                            const void *data, const size_t datalen, const RIL_Token t) {
    182     int status;
    183     Buffer *buffer;
    184     v8::HandleScope handle_scope;
    185 
    186     DBG("ReqSeparateConnection E");
    187     if (datalen < sizeof(int)) {
    188         LOGE("ReqSetMute: data to small err size < sizeof int");
    189         status = STATUS_BAD_DATA;
    190     } else {
    191         ril_proto::ReqSeparateConnection *req = new ril_proto::ReqSeparateConnection();
    192         DBG("ReqSeparateConnection: index=%d", ((int *)data)[0]);
    193         req->set_index(((int *)data)[0]);
    194         DBG("ReqSeparateConnection: req->ByetSize=%d", req->ByteSize());
    195         buffer = Buffer::New(req->ByteSize());
    196         req->SerializeToArray(buffer->data(), buffer->length());
    197         delete req;
    198         *pBuffer = buffer;
    199         status = STATUS_OK;
    200     }
    201     DBG("ReqSeparateConnection X status=%d", status);
    202     return status;
    203 }
    204 
    205 /**
    206  * request for RIL_REQUEST_SET_MUTE      // 53
    207  */
    208 int ReqSetMute(Buffer **pBuffer,
    209                const void *data, const size_t datalen, const RIL_Token t) {
    210     int status;
    211     Buffer *buffer;
    212     v8::HandleScope handle_scope;
    213 
    214     DBG("ReqSetMute E");
    215     if (datalen < sizeof(int)) {
    216         LOGE("ReqSetMute: data to small err size < sizeof int");
    217         status = STATUS_BAD_DATA;
    218     } else {
    219         ril_proto::ReqSetMute *req = new ril_proto::ReqSetMute();
    220         DBG("ReqSetMute: state=%d", ((int *)data)[0]);
    221         req->set_state(((int *)data)[0]);
    222         DBG("ReqSetMute: req->ByetSize=%d", req->ByteSize());
    223         buffer = Buffer::New(req->ByteSize());
    224         req->SerializeToArray(buffer->data(), buffer->length());
    225         delete req;
    226         *pBuffer = buffer;
    227         status = STATUS_OK;
    228     }
    229     DBG("ReqSetMute X status=%d", status);
    230     return status;
    231 }
    232 
    233 /**
    234  * request for RIL_REQUEST_SCREEN_STATE  // 61
    235  */
    236 int ReqScreenState(Buffer **pBuffer,
    237         const void *data, const size_t datalen, const RIL_Token t) {
    238     int status;
    239     Buffer *buffer;
    240     v8::HandleScope handle_scope;
    241 
    242     DBG("ReqScreenState E data=%p datalen=%d t=%p",
    243          data, datalen, t);
    244     if (datalen < sizeof(int)) {
    245         LOGE("ReqScreenState: data to small err size < sizeof int");
    246         status = STATUS_BAD_DATA;
    247     } else {
    248         ril_proto::ReqScreenState *req = new ril_proto::ReqScreenState();
    249         DBG("ReqScreenState: state=%d", ((int *)data)[0]);
    250         req->set_state(((int *)data)[0]);
    251         DBG("ReqScreenState: req->ByteSize()=%d", req->ByteSize());
    252         buffer = Buffer::New(req->ByteSize());
    253         DBG("ReqScreenState: serialize");
    254         req->SerializeToArray(buffer->data(), buffer->length());
    255         delete req;
    256         *pBuffer = buffer;
    257         status = STATUS_OK;
    258     }
    259     DBG("ReqScreenState X status=%d", status);
    260     return status;
    261 }
    262 
    263 /**
    264  * Map from indexed by cmd and used to convert Data to Protobuf.
    265  */
    266 typedef int (*ReqConversion)(Buffer** pBuffer, const void *data,
    267                 const size_t datalen, const RIL_Token t);
    268 typedef std::map<int, ReqConversion> ReqConversionMap;
    269 ReqConversionMap rilReqConversionMap;
    270 
    271 int callOnRilRequest(v8::Handle<v8::Context> context, int cmd,
    272                    const void *buffer, RIL_Token t) {
    273     DBG("callOnRilRequest E: cmd=%d", cmd);
    274 
    275     int status;
    276     v8::HandleScope handle_scope;
    277     v8::TryCatch try_catch;
    278 
    279     // Get the onRilRequest Function
    280     v8::Handle<v8::String> name = v8::String::New("onRilRequest");
    281     v8::Handle<v8::Value> onRilRequestFunctionValue = context->Global()->Get(name);
    282     v8::Handle<v8::Function> onRilRequestFunction =
    283         v8::Handle<v8::Function>::Cast(onRilRequestFunctionValue);
    284 
    285     // Create the cmd and token
    286     v8::Handle<v8::Value> v8RequestValue = v8::Number::New(cmd);
    287     v8::Handle<v8::Value> v8TokenValue = v8::Number::New(int64_t(t));
    288 
    289     // Invoke onRilRequest
    290     const int argc = 3;
    291     v8::Handle<v8::Value> argv[argc] = {
    292             v8RequestValue, v8TokenValue, ((Buffer *)buffer)->handle_ };
    293     v8::Handle<v8::Value> result =
    294         onRilRequestFunction->Call(context->Global(), argc, argv);
    295     if (try_catch.HasCaught()) {
    296         LOGE("callOnRilRequest error");
    297         ReportException(&try_catch);
    298         status = STATUS_ERR;
    299     } else {
    300         v8::String::Utf8Value result_string(result);
    301         DBG("callOnRilRequest result=%s", ToCString(result_string));
    302         status = STATUS_OK;
    303     }
    304 
    305     DBG("callOnRilRequest X: status=%d", status);
    306     return status;
    307 }
    308 
    309 RilRequestWorkerQueue::RilRequestWorkerQueue(v8::Handle<v8::Context> context) {
    310     DBG("RilRequestWorkerQueue E:");
    311 
    312     context_ = context;
    313     pthread_mutex_init(&free_list_mutex_, NULL);
    314 
    315     DBG("RilRequestWorkerQueue X:");
    316 }
    317 
    318 RilRequestWorkerQueue::~RilRequestWorkerQueue() {
    319     DBG("~RilRequestWorkerQueue E:");
    320     Request *req;
    321     pthread_mutex_lock(&free_list_mutex_);
    322     while(free_list_.size() != 0) {
    323         req = free_list_.front();
    324         delete req;
    325         free_list_.pop();
    326     }
    327     pthread_mutex_unlock(&free_list_mutex_);
    328     pthread_mutex_destroy(&free_list_mutex_);
    329     DBG("~RilRequestWorkerQueue X:");
    330 }
    331 
    332 /**
    333  * Add a request to the processing queue.
    334  * Data is serialized to a protobuf before adding to the queue.
    335  */
    336 void RilRequestWorkerQueue::AddRequest (const int request,
    337         const void *data, const size_t datalen, const RIL_Token token) {
    338     DBG("RilRequestWorkerQueue:AddRequest: %d E", request);
    339 
    340     v8::Locker locker;
    341     v8::HandleScope handle_scope;
    342     v8::Context::Scope context_scope(context_);
    343 
    344     int status;
    345 
    346     // Convert the data to a protobuf before inserting it into the request queue (serialize data)
    347     Buffer *buffer = NULL;
    348     ReqConversionMap::iterator itr;
    349     itr = rilReqConversionMap.find(request);
    350     if (itr != rilReqConversionMap.end()) {
    351         status = itr->second(&buffer, data, datalen, token);
    352     } else {
    353         LOGE("RilRequestWorkerQueue:AddRequest: X unknown request %d", request);
    354         status = STATUS_UNSUPPORTED_REQUEST;
    355     }
    356 
    357     if (status == STATUS_OK) {
    358         // Add serialized request to the queue
    359         Request *req;
    360         pthread_mutex_lock(&free_list_mutex_);
    361         DBG("RilRequestWorkerQueue:AddRequest: return ok, buffer = %p, buffer->length()=%d",
    362             buffer, buffer->length());
    363         if (free_list_.size() == 0) {
    364             req = new Request(request, buffer, token);
    365             pthread_mutex_unlock(&free_list_mutex_);
    366         } else {
    367             req = free_list_.front();
    368             free_list_.pop();
    369             pthread_mutex_unlock(&free_list_mutex_);
    370             req->Set(request, buffer, token);
    371         }
    372         // add the request
    373         Add(req);
    374     } else {
    375         DBG("RilRequestWorkerQueue:AddRequest: return from the serialization, status is not OK");
    376         // An error report complete now
    377         RIL_Errno rilErrCode = (status == STATUS_UNSUPPORTED_REQUEST) ?
    378                  RIL_E_REQUEST_NOT_SUPPORTED : RIL_E_GENERIC_FAILURE;
    379         s_rilenv->OnRequestComplete(token, rilErrCode, NULL, 0);
    380     }
    381 
    382     DBG("RilRequestWorkerQueue::AddRequest: X"
    383          " request=%d data=%p datalen=%d token=%p",
    384             request, data, datalen, token);
    385 }
    386 
    387 void RilRequestWorkerQueue::Process(void *p) {
    388 
    389     Request *req = (Request *)p;
    390     DBG("RilRequestWorkerQueue::Process: E"
    391          " request=%d buffer=%p, bufferlen=%d t=%p",
    392             req->request_, req->buffer_, req->buffer_->length(), req->token_);
    393 
    394     v8::Locker locker;
    395     v8::HandleScope handle_scope;
    396     v8::Context::Scope context_scope(context_);
    397     callOnRilRequest(context_, req->request_,
    398                           req->buffer_, req->token_);
    399 
    400     pthread_mutex_lock(&free_list_mutex_);
    401     free_list_.push(req);
    402     pthread_mutex_unlock(&free_list_mutex_);
    403 }
    404 
    405 int requestsInit(v8::Handle<v8::Context> context, RilRequestWorkerQueue **rwq) {
    406     LOGD("requestsInit E");
    407 
    408     rilReqConversionMap[RIL_REQUEST_GET_SIM_STATUS] = ReqWithNoData; // 1
    409     rilReqConversionMap[RIL_REQUEST_ENTER_SIM_PIN] = ReqEnterSimPin; // 2
    410     rilReqConversionMap[RIL_REQUEST_GET_CURRENT_CALLS] = ReqWithNoData; // 9
    411     rilReqConversionMap[RIL_REQUEST_DIAL] = ReqDial;   // 10
    412     rilReqConversionMap[RIL_REQUEST_GET_IMSI] = ReqWithNoData; // 11
    413     rilReqConversionMap[RIL_REQUEST_HANGUP] = ReqHangUp; // 12
    414     rilReqConversionMap[RIL_REQUEST_HANGUP_WAITING_OR_BACKGROUND] = ReqWithNoData; // 13
    415     rilReqConversionMap[RIL_REQUEST_HANGUP_FOREGROUND_RESUME_BACKGROUND] = ReqWithNoData; // 14
    416     rilReqConversionMap[RIL_REQUEST_SWITCH_WAITING_OR_HOLDING_AND_ACTIVE] = ReqWithNoData; // 15
    417     rilReqConversionMap[RIL_REQUEST_CONFERENCE] = ReqWithNoData;  // 16
    418     rilReqConversionMap[RIL_REQUEST_LAST_CALL_FAIL_CAUSE] = ReqWithNoData;  // 18
    419     rilReqConversionMap[RIL_REQUEST_SIGNAL_STRENGTH] = ReqWithNoData; // 19
    420     rilReqConversionMap[RIL_REQUEST_REGISTRATION_STATE] = ReqWithNoData; // 20
    421     rilReqConversionMap[RIL_REQUEST_GPRS_REGISTRATION_STATE] = ReqWithNoData; // 21
    422     rilReqConversionMap[RIL_REQUEST_OPERATOR] = ReqWithNoData; // 22
    423     rilReqConversionMap[RIL_REQUEST_GET_IMEI] = ReqWithNoData; // 38
    424     rilReqConversionMap[RIL_REQUEST_GET_IMEISV] = ReqWithNoData; // 39
    425     rilReqConversionMap[RIL_REQUEST_ANSWER] = ReqWithNoData; // 40
    426     rilReqConversionMap[RIL_REQUEST_QUERY_NETWORK_SELECTION_MODE] = ReqWithNoData; // 45
    427     rilReqConversionMap[RIL_REQUEST_SET_NETWORK_SELECTION_AUTOMATIC] = ReqWithNoData; // 46
    428     rilReqConversionMap[RIL_REQUEST_BASEBAND_VERSION] = ReqWithNoData; // 51
    429     rilReqConversionMap[RIL_REQUEST_SEPARATE_CONNECTION] = ReqSeparateConnection; // 52
    430     rilReqConversionMap[RIL_REQUEST_SET_MUTE] = ReqSetMute; // 53
    431     rilReqConversionMap[RIL_REQUEST_SCREEN_STATE] = ReqScreenState; // 61
    432 
    433     *rwq = new RilRequestWorkerQueue(context);
    434     int status = (*rwq)->Run();
    435 
    436     LOGD("requestsInit X: status=%d", status);
    437     return status;
    438 }
    439 
    440 /**
    441  * Subroutine to test a single RIL request
    442  */
    443 void testRilRequest(v8::Handle<v8::Context> context, int request, const void *data,
    444                     const size_t datalen, const RIL_Token t) {
    445     Buffer *buffer = NULL;
    446     ReqConversionMap::iterator itr;
    447     int status;
    448 
    449     LOGD("testRilRequest: request=%d", request);
    450 
    451     itr = rilReqConversionMap.find(request);
    452     if (itr != rilReqConversionMap.end()) {
    453         status = itr->second(&buffer, data, sizeof(data), (void *)0x12345677);
    454     } else {
    455         LOGE("testRequests X unknown request %d", request);
    456         status = STATUS_UNSUPPORTED_REQUEST;
    457     }
    458     if (status == STATUS_OK) {
    459         callOnRilRequest(context, request, buffer, (void *)0x12345677);
    460     } else {
    461         LOGE("testRilRequest X, serialize error");
    462     }
    463 }
    464 
    465 void testRequests(v8::Handle<v8::Context> context) {
    466     LOGD("testRequests E: ********");
    467 
    468     v8::TryCatch try_catch;
    469 
    470     char *buffer;
    471     const char *fileName= "/sdcard/data/mock_ril.js";
    472     int status = ReadFile(fileName, &buffer);
    473     if (status == 0) {
    474         runJs(context, &try_catch, fileName, buffer);
    475         Buffer *buffer = NULL;
    476         ReqConversionMap::iterator itr;
    477         int status;
    478         int request;
    479 
    480         if (!try_catch.HasCaught()) {
    481             {
    482                 const int data[1] = { 1 };
    483                 testRilRequest(context, RIL_REQUEST_SIGNAL_STRENGTH, data, sizeof(data),
    484                                (void *)0x12345677);
    485             }
    486             {
    487                 const char *data[1] = { "winks-pin" };
    488                 testRilRequest(context, RIL_REQUEST_ENTER_SIM_PIN, data, sizeof(data),
    489                                (void *)0x12345677);
    490             }
    491             {
    492                 const int data[1] = { 1 };
    493                 testRilRequest(context, RIL_REQUEST_HANGUP, data, sizeof(data),
    494                                (void *)0x12345677);
    495             }
    496             {
    497                 const int data[1] = { 1 };
    498                 testRilRequest(context, RIL_REQUEST_SCREEN_STATE, data, sizeof(data),
    499                                (void *)0x12345677);
    500             }
    501             {
    502                 const int data[1] = { 1 };
    503                 testRilRequest(context, RIL_REQUEST_GET_SIM_STATUS, data, sizeof(data),
    504                                (void *)0x12345677);
    505             }
    506             {
    507                 RilRequestWorkerQueue *rwq = new RilRequestWorkerQueue(context);
    508                 if (rwq->Run() == STATUS_OK) {
    509                     const int data[1] = { 1 };
    510                     rwq->AddRequest(RIL_REQUEST_SCREEN_STATE,
    511                                     data, sizeof(data), (void *)0x1234567A);
    512                     rwq->AddRequest(RIL_REQUEST_SIGNAL_STRENGTH,
    513                                     data, sizeof(data), (void *)0x1234567A);
    514                     // Sleep to let it be processed
    515                     v8::Unlocker unlocker;
    516                     sleep(3);
    517                     v8::Locker locker;
    518                 }
    519                 delete rwq;
    520             }
    521         }
    522     }
    523 
    524     LOGD("testRequests X: ********\n");
    525 }
    526