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 */
53int 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 */
69int 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 */
95int 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 */
154int 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 */
180int 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 */
208int 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 */
236int 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 */
266typedef int (*ReqConversion)(Buffer** pBuffer, const void *data,
267                const size_t datalen, const RIL_Token t);
268typedef std::map<int, ReqConversion> ReqConversionMap;
269ReqConversionMap rilReqConversionMap;
270
271int 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
309RilRequestWorkerQueue::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
318RilRequestWorkerQueue::~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 */
336void 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
387void 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
405int 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 */
443void 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
465void 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