• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "ril.h"
21 
22 
23 #include "hardware/ril/mock-ril/src/proto/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(...) ALOGD(__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  */
ReqWithNoData(Buffer ** pBuffer,const void * data,const size_t datalen,const RIL_Token t)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  */
ReqEnterSimPin(Buffer ** pBuffer,const void * data,const size_t datalen,const RIL_Token t)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         ALOGE("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  */
ReqDial(Buffer ** pBuffer,const void * data,const size_t datalen,const RIL_Token t)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         ALOGE("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  */
ReqHangUp(Buffer ** pBuffer,const void * data,const size_t datalen,const RIL_Token t)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         ALOGE("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  */
ReqSeparateConnection(Buffer ** pBuffer,const void * data,const size_t datalen,const RIL_Token t)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         ALOGE("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  */
ReqSetMute(Buffer ** pBuffer,const void * data,const size_t datalen,const RIL_Token t)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         ALOGE("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  */
ReqScreenState(Buffer ** pBuffer,const void * data,const size_t datalen,const RIL_Token t)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         ALOGE("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 
callOnRilRequest(v8::Handle<v8::Context> context,int cmd,const void * buffer,RIL_Token t)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         ALOGE("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 
RilRequestWorkerQueue(v8::Handle<v8::Context> context)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 
~RilRequestWorkerQueue()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  */
AddRequest(const int request,const void * data,const size_t datalen,const RIL_Token token)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         ALOGE("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 
Process(void * p)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 
requestsInit(v8::Handle<v8::Context> context,RilRequestWorkerQueue ** rwq)405 int requestsInit(v8::Handle<v8::Context> context, RilRequestWorkerQueue **rwq) {
406     ALOGD("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_VOICE_REGISTRATION_STATE] = ReqWithNoData; // 20
421     rilReqConversionMap[RIL_REQUEST_DATA_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     ALOGD("requestsInit X: status=%d", status);
437     return status;
438 }
439 
440 /**
441  * Subroutine to test a single RIL request
442  */
testRilRequest(v8::Handle<v8::Context> context,int request,const void * data,const size_t datalen,const RIL_Token t)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     ALOGD("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         ALOGE("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         ALOGE("testRilRequest X, serialize error");
462     }
463 }
464 
testRequests(v8::Handle<v8::Context> context)465 void testRequests(v8::Handle<v8::Context> context) {
466     ALOGD("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     ALOGD("testRequests X: ********\n");
525 }
526