/** * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include <telephony/ril.h> #include <stdio.h> #include <assert.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <pthread.h> #include <alloca.h> #include <getopt.h> #include <sys/socket.h> #include <cutils/sockets.h> #include <termios.h> #include <v8.h> #include "ril.pb.h" #include "ctrl_server.h" #include "logging.h" #include "experiments.h" #include "js_support.h" #include "node_buffer.h" #include "node_object_wrap.h" #include "node_util.h" #include "protobuf_v8.h" #include "requests.h" #include "responses.h" #include "status.h" #include "util.h" #include "worker.h" #include "worker_v8.h" #include "mock_ril.h" extern "C" { // Needed so we can call it prior to calling startMockRil extern void RIL_register(const RIL_RadioFunctions *callbacks); } //#define MOCK_RIL_DEBUG #ifdef MOCK_RIL_DEBUG #define DBG(...) LOGD(__VA_ARGS__) #else #define DBG(...) #endif #define MOCK_RIL_VER_STRING "Android Mock-ril 0.1" /** * Forward declarations */ static void onRequest (int request, void *data, size_t datalen, RIL_Token t); static RIL_RadioState currentState(); static int onSupports (int requestCode); static void onCancel (RIL_Token t); static const char *getVersion(); static void testOnRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen); static void testRequestTimedCallback(RIL_TimedCallback callback, void *param, const struct timeval *relativeTime); static void testOnUnsolicitedResponse(int unsolResponse, const void *data, size_t datalen); /** * The environment from rild with the completion routine */ const struct RIL_Env *s_rilenv; /** * Expose our routines to rild */ static const RIL_RadioFunctions s_callbacks = { RIL_VERSION, onRequest, currentState, onSupports, onCancel, getVersion }; /** * A test environment */ static const RIL_Env testEnv = { testOnRequestComplete, testOnUnsolicitedResponse, testRequestTimedCallback }; /** * The request worker queue to handle requests */ static RilRequestWorkerQueue *s_requestWorkerQueue; /** * Call from RIL to us to make a RIL_REQUEST * * Must be completed with a call to RIL_onRequestComplete() * * RIL_onRequestComplete() may be called from any thread, before or after * this function returns. * * Will always be called from the same thread, so returning here implies * that the radio is ready to process another command (whether or not * the previous command has c1mpleted). */ static void onRequest (int request, void *data, size_t datalen, RIL_Token t) { DBG("onRequest: request=%d data=%p datalen=%d token=%p", request, data, datalen, t); s_requestWorkerQueue->AddRequest(request, data, datalen, t); } /** * Synchronous call from the RIL to us to return current radio state. * RADIO_STATE_UNAVAILABLE should be the initial state. */ static RIL_RadioState currentState() { DBG("currentState: gRadioState=%d", gRadioState); return gRadioState; } /** * Call from RIL to us to find out whether a specific request code * is supported by this implementation. * * Return 1 for "supported" and 0 for "unsupported" */ static int onSupports (int requestCode) { DBG("onSupports: nothing supported at the moment, return 0"); return 0; } static void onCancel (RIL_Token t) { DBG("onCancel: ignorning"); } static const char * getVersion(void) { DBG("getVersion: return '%s'", MOCK_RIL_VER_STRING); return MOCK_RIL_VER_STRING; } /** * "t" is parameter passed in on previous call to RIL_Notification * routine. * * If "e" != SUCCESS, then response can be null/is ignored * * "response" is owned by caller, and should not be modified or * freed by callee * * RIL_onRequestComplete will return as soon as possible */ void testOnRequestComplete(RIL_Token t, RIL_Errno e, void *response, size_t responselen) { DBG("testOnRequestComplete E: token=%p rilErrCode=%d data=%p datalen=%d", t, e, response, responselen); DBG("testOnRequestComplete X:"); } /** * "unsolResponse" is one of RIL_UNSOL_RESPONSE_* * "data" is pointer to data defined for that RIL_UNSOL_RESPONSE_* * * "data" is owned by caller, and should not be modified or freed by callee */ void testOnUnsolicitedResponse(int unsolResponse, const void *data, size_t datalen) { DBG("testOnUnsolicitedResponse ignoring"); } /** * Call user-specifed "callback" function on on the same thread that * RIL_RequestFunc is called. If "relativeTime" is specified, then it specifies * a relative time value at which the callback is invoked. If relativeTime is * NULL or points to a 0-filled structure, the callback will be invoked as * soon as possible */ void testRequestTimedCallback(RIL_TimedCallback callback, void *param, const struct timeval *relativeTime) { DBG("testRequestTimedCallback ignoring"); } #if 0 class UnsolicitedThread : public WorkerThread { private: v8::Handle<v8::Context> context_; public: UnsolicitedThread(v8::Handle<v8::Context> context) : context_(context) { } int OnUnsolicitedTick(int tick) { v8::HandleScope handle_scope; // Get handle to onUnslicitedTick. v8::Handle<v8::String> name = v8::String::New("onUnsolicitedTick"); v8::Handle<v8::Value> functionValue = context_->Global()->Get(name); v8::Handle<v8::Function> onUnsolicitedTick = v8::Handle<v8::Function>::Cast(functionValue); // Create the argument array v8::Handle<v8::Value> v8TickValue = v8::Number::New(tick); v8::Handle<v8::Value> argv[1] = { v8TickValue }; v8::Handle<v8::Value> resultValue = onUnsolicitedTick->Call(context_->Global(), 1, argv); int result = int(resultValue->NumberValue()); return result; } void * Worker(void *param) { LOGD("UnsolicitedThread::Worker E param=%p", param); v8::Locker locker; for (int i = 0; isRunning(); i++) { // Get access and setup scope v8::HandleScope handle_scope; v8::Context::Scope context_scope(context_); // Do it int sleepTime = OnUnsolicitedTick(i); // Wait v8::Unlocker unlocker; sleep(sleepTime); v8::Locker locker; } LOGD("UnsolicitedThread::Worker X param=%p", param); return NULL; } }; #endif void startMockRil(v8::Handle<v8::Context> context) { v8::HandleScope handle_scope; v8::TryCatch try_catch; // Get handle to startMockRil and call it. v8::Handle<v8::String> name = v8::String::New("startMockRil"); v8::Handle<v8::Value> functionValue = context->Global()->Get(name); v8::Handle<v8::Function> start = v8::Handle<v8::Function>::Cast(functionValue); v8::Handle<v8::Value> result = start->Call(context->Global(), 0, NULL); if (try_catch.HasCaught()) { LOGE("startMockRil error"); ReportException(&try_catch); LOGE("FATAL ERROR: Unsable to startMockRil."); } else { v8::String::Utf8Value result_string(result); LOGE("startMockRil result=%s", ToCString(result_string)); } } const RIL_RadioFunctions *RIL_Init(const struct RIL_Env *env, int argc, char **argv) { int ret; pthread_attr_t attr; LOGD("RIL_Init E: ----------------"); // Initialize V8 v8::V8::Initialize(); // We're going to use multiple threads need to start locked v8::Locker locker; // Initialize modules protobuf_v8::Init(); WorkerV8Init(); // Make a context and setup a scope v8::Persistent<v8::Context> context = makeJsContext(); v8::Context::Scope context_scope(context); v8::TryCatch try_catch; try_catch.SetVerbose(true); // Initialize modules needing context ctrlServerInit(context); s_rilenv = &testEnv; // load/run mock_ril.js char *buffer; int status = ReadFile("/sdcard/data/mock_ril.js", &buffer); if (status == 0) { runJs(context, &try_catch, "mock_ril.js", buffer); if (try_catch.HasCaught()) { // TODO: Change to event this is fatal LOGE("FATAL ERROR: Unable to run mock_ril.js"); } } s_rilenv = env; requestsInit(context, &s_requestWorkerQueue); responsesInit(context); #if 0 LOGD("RIL_Init run tests #####################"); testJsSupport(context); testRequests(context); experiments(context); testWorker(); testWorkerV8(context); LOGD("RIL_Init tests completed ###############"); #endif // Register our call backs so when we startMockRil // and it wants to send unsolicited messages the // mock ril is registered RIL_register(&s_callbacks); // Start the mock ril startMockRil(context); #if 0 UnsolicitedThread *ut = new UnsolicitedThread(context); ut->Run(NULL); #endif LOGD("RIL_Init X: ----------------"); return &s_callbacks; }