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