OSDN Git Service

Port Mock Ril from master branch to GB. DO NOT MERGE
[android-x86/hardware-ril.git] / mock-ril / src / cpp / js_support.cpp
diff --git a/mock-ril/src/cpp/js_support.cpp b/mock-ril/src/cpp/js_support.cpp
new file mode 100644 (file)
index 0000000..9497176
--- /dev/null
@@ -0,0 +1,415 @@
+/**
+ * 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 <v8.h>
+#include <telephony/ril.h>
+
+#include "ctrl_server.h"
+#include "logging.h"
+#include "node_buffer.h"
+#include "node_object_wrap.h"
+#include "node_util.h"
+#include "protobuf_v8.h"
+#include "responses.h"
+#include "status.h"
+#include "util.h"
+#include "worker.h"
+#include "worker_v8.h"
+
+#include "js_support.h"
+
+//#define JS_SUPPORT_DEBUG
+#ifdef  JS_SUPPORT_DEBUG
+
+#define DBG(...) LOGD(__VA_ARGS__)
+
+#else
+
+#define DBG(...)
+
+#endif
+
+/**
+ * Current Radio state
+ */
+RIL_RadioState gRadioState = RADIO_STATE_UNAVAILABLE;
+
+v8::Handle<v8::Value> RadioStateGetter(v8::Local<v8::String> property,
+        const v8::AccessorInfo& info) {
+    return v8::Integer::New((int)gRadioState);
+}
+
+void RadioStateSetter(v8::Local<v8::String> property,
+        v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
+    gRadioState = RIL_RadioState(value->Int32Value());
+}
+
+// A javascript sleep for a number of milli-seconds
+v8::Handle<v8::Value> MsSleep(const v8::Arguments& args) {
+    if (args.Length() != 1) {
+        DBG("MsSleep: expecting milli-seconds to sleep");
+    } else {
+        v8::Handle<v8::Value> v8MsValue(args[0]->ToObject());
+        int ms = int(v8MsValue->NumberValue());
+        v8::Unlocker unlocker;
+        usleep(ms * 1000);
+        v8::Locker locker;
+    }
+    return v8::Undefined();
+}
+
+// A javascript print function
+v8::Handle<v8::Value> Print(const v8::Arguments& args) {
+    bool first = true;
+    const int str_size = 1000;
+    char* str = new char[str_size];
+    int offset = 0;
+    for (int i = 0; i < args.Length(); i++) {
+        v8::HandleScope handle_scope;
+        if (first) {
+            first = false;
+        } else {
+            offset += snprintf(&str[offset], str_size, " ");
+        }
+        v8::String::Utf8Value strUtf8(args[i]);
+        const char* cstr = ToCString(strUtf8);
+        offset += snprintf(&str[offset], str_size, "%s", cstr);
+    }
+    LOGD("%s", str);
+    delete [] str;
+    return v8::Undefined();
+}
+
+int ReadFile(const char *fileName, char** data, size_t *length) {
+    int status;
+    char* buffer = NULL;
+    size_t fileLength = 0;
+    FILE *f;
+
+    DBG("ReadFile E fileName=%s", fileName);
+
+    f = fopen(fileName, "rb");
+    if (f == NULL) {
+        DBG("Could not fopen '%s'", fileName);
+        status = STATUS_COULD_NOT_OPEN_FILE;
+    } else {
+        // Determine the length of the file
+        fseek(f, 0, SEEK_END);
+        fileLength = ftell(f);
+        DBG("fileLength=%d", fileLength);
+        rewind(f);
+
+        // Read file into a buffer
+        buffer = new char[fileLength+1];
+        size_t readLength = fread(buffer, 1, fileLength, f);
+        if (readLength != fileLength) {
+            DBG("Couldn't read entire file");
+            delete [] buffer;
+            buffer = NULL;
+            status = STATUS_COULD_NOT_READ_FILE;
+        } else {
+            DBG("File read");
+            buffer[fileLength] = 0;
+            status = STATUS_OK;
+        }
+        fclose(f);
+    }
+
+    if (length != NULL) {
+        *length = fileLength;
+    }
+    *data = buffer;
+    DBG("ReadFile X status=%d", status);
+    return status;
+}
+
+char *CreateFileName(const v8::Arguments& args) {
+    v8::String::Utf8Value fileNameUtf8Value(args[0]);
+    const char* fileName = ToCString(fileNameUtf8Value);
+    const char* directory = "/sdcard/data/";
+
+    int fullPathLength = strlen(directory) + strlen(fileName) + 1;
+    char * fullPath = new char[fullPathLength];
+    strncpy(fullPath, directory, fullPathLength);
+    strncat(fullPath, fileName, fullPathLength);
+    return fullPath;
+}
+
+// A javascript read file function arg[0] = filename
+v8::Handle<v8::Value> ReadFileToString(const v8::Arguments& args) {
+    DBG("ReadFileToString E");
+    v8::HandleScope handle_scope;
+    v8::Handle<v8::Value> retValue;
+
+    if (args.Length() < 1) {
+        // No file name return Undefined
+        DBG("ReadFile X no argumens");
+        return v8::Undefined();
+    } else {
+        char *fileName = CreateFileName(args);
+
+        char *buffer;
+        int status = ReadFile(fileName, &buffer);
+        if (status == 0) {
+            retValue = v8::String::New(buffer);
+        } else {
+            retValue = v8::Undefined();
+        }
+    }
+    DBG("ReadFileToString X");
+    return retValue;
+}
+
+// A javascript read file function arg[0] = filename
+v8::Handle<v8::Value> ReadFileToBuffer(const v8::Arguments& args) {
+    DBG("ReadFileToBuffer E");
+    v8::HandleScope handle_scope;
+    v8::Handle<v8::Value> retValue;
+
+    if (args.Length() < 1) {
+        // No file name return Undefined
+        DBG("ReadFileToBuffer X no argumens");
+        return v8::Undefined();
+    } else {
+        char *fileName = CreateFileName(args);
+
+        char *buffer;
+        size_t length;
+        int status = ReadFile(fileName, &buffer, &length);
+        if (status == 0) {
+            Buffer *buf = Buffer::New(length);
+            memmove(buf->data(), buffer, length);
+            retValue = buf->handle_;
+        } else {
+            retValue = v8::Undefined();
+        }
+    }
+    DBG("ReadFileToBuffer X");
+    return retValue;
+}
+
+void ErrorCallback(v8::Handle<v8::Message> message,
+        v8::Handle<v8::Value> data) {
+    LogErrorMessage(message, "");
+}
+
+// Read, compile and run a javascript file
+v8::Handle<v8::Value> Include(const v8::Arguments& args) {
+    DBG("Include E");
+    v8::HandleScope handle_scope;
+    v8::Handle<v8::Value> retValue;
+    v8::TryCatch try_catch;
+    try_catch.SetVerbose(true);
+
+    if (args.Length() < 1) {
+        // No file name return Undefined
+        DBG("Include X no argumens");
+        return v8::Undefined();
+    } else {
+        char *fileName = CreateFileName(args);
+
+        char *buffer;
+        int status = ReadFile(fileName, &buffer);
+        if (status == 0) {
+            runJs(v8::Context::GetCurrent(), &try_catch, fileName, buffer);
+        } else {
+            retValue = v8::Undefined();
+        }
+    }
+    DBG("Include X");
+    return retValue;
+}
+
+
+/**
+ * Create a JsContext, must be called within a HandleScope?
+ */
+v8::Persistent<v8::Context> makeJsContext() {
+    v8::HandleScope handle_scope;
+    v8::TryCatch try_catch;
+
+    // Add a Message listner to Catch errors as they occur
+    v8::V8::AddMessageListener(ErrorCallback);
+
+    // Create a template for the global object and
+    // add the function template for print to it.
+    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
+    global->SetAccessor(v8::String::New("gRadioState"),
+            RadioStateGetter, RadioStateSetter);
+    global->Set(v8::String::New("msSleep"), v8::FunctionTemplate::New(MsSleep));
+    global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
+    global->Set(v8::String::New("readFileToBuffer"),
+            v8::FunctionTemplate::New(ReadFileToBuffer));
+    global->Set(v8::String::New("readFileToString"),
+            v8::FunctionTemplate::New(ReadFileToString));
+    global->Set(v8::String::New("sendRilRequestComplete"),
+            v8::FunctionTemplate::New(SendRilRequestComplete));
+    global->Set(v8::String::New("sendRilUnsolicitedResponse"),
+            v8::FunctionTemplate::New(SendRilUnsolicitedResponse));
+    global->Set(v8::String::New("sendCtrlRequestComplete"),
+            v8::FunctionTemplate::New(SendCtrlRequestComplete));
+    global->Set(v8::String::New("include"), v8::FunctionTemplate::New(Include));
+    WorkerV8ObjectTemplateInit(global);
+    SchemaObjectTemplateInit(global);
+    Buffer::InitializeObjectTemplate(global);
+
+    // Create context with our globals and make it the current scope
+    v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
+
+
+    if (try_catch.HasCaught()) {
+        DBG("makeJsContext: Exception making the context");
+        ReportException(&try_catch);
+        try_catch.ReThrow();
+    }
+
+    return context;
+}
+
+/**
+ * Run some javascript code.
+ */
+void runJs(v8::Handle<v8::Context> context, v8::TryCatch *try_catch,
+        const char *fileName, const char *code) {
+    v8::HandleScope handle_scope;
+
+    // Compile the source
+    v8::Handle<v8::Script> script = v8::Script::Compile(
+                v8::String::New(code), v8::String::New(fileName));
+    if (try_catch->HasCaught()) {
+        LOGE("-- Compiling the source failed");
+    } else {
+        // Run the resulting script
+        v8::Handle<v8::Value> result = script->Run();
+        if (try_catch->HasCaught()) {
+            LOGE("-- Running the script failed");
+        }
+    }
+}
+
+void testRadioState(v8::Handle<v8::Context> context) {
+    LOGD("testRadioState E:");
+    v8::HandleScope handle_scope;
+
+    v8::TryCatch try_catch;
+    try_catch.SetVerbose(true);
+
+    runJs(context, &try_catch, "local-string",
+        "for(i = 0; i < 10; i++) {\n"
+        "  gRadioState = i;\n"
+        "  print('gRadioState=' + gRadioState);\n"
+        "}\n"
+        "gRadioState = 1;\n"
+        "print('last gRadioState=' + gRadioState);\n");
+    LOGD("testRadioState X:");
+}
+
+void testMsSleep(v8::Handle<v8::Context> context) {
+    LOGD("testMsSleep E:");
+    v8::HandleScope handle_scope;
+
+    v8::TryCatch try_catch;
+    try_catch.SetVerbose(true);
+
+    runJs(context, &try_catch, "local-string",
+        "for(i = 0; i < 10; i++) {\n"
+        "  sleeptime = i * 200\n"
+        "  print('msSleep ' + sleeptime);\n"
+        "  msSleep(sleeptime);\n"
+        "}\n");
+    LOGD("testMsSleep X:");
+}
+
+void testPrint(v8::Handle<v8::Context> context) {
+    LOGD("testPrint E:");
+    v8::HandleScope handle_scope;
+
+    v8::TryCatch try_catch;
+    try_catch.SetVerbose(true);
+
+    runJs(context, &try_catch, "local-string", "print(\"Hello\")");
+    LOGD("testPrint X:");
+}
+
+void testCompileError(v8::Handle<v8::Context> context) {
+    LOGD("testCompileError E:");
+    v8::HandleScope handle_scope;
+
+    v8::TryCatch try_catch;
+    try_catch.SetVerbose(true);
+
+    // +++ generate a compile time error
+    runJs(context, &try_catch, "local-string", "+++");
+    LOGD("testCompileError X:");
+}
+
+void testRuntimeError(v8::Handle<v8::Context> context) {
+    LOGD("testRuntimeError E:");
+    v8::HandleScope handle_scope;
+
+    v8::TryCatch try_catch;
+    try_catch.SetVerbose(true);
+
+    // Runtime error
+    runJs(context, &try_catch, "local-string",
+        "function hello() {\n"
+        "  print(\"Hi there\");\n"
+        "}\n"
+        "helloo()");
+    LOGD("testRuntimeError X:");
+}
+
+void testReadFile() {
+    char *buffer;
+    size_t length;
+    int status;
+
+    LOGD("testReadFile E:");
+
+    status = ReadFile("/sdcard/data/no-file", &buffer, &length);
+    LOGD("testReadFile expect status != 0, status=%d, buffer=%p, length=%d",
+            status, buffer, length);
+
+    LOGD("testReadFile X:");
+}
+
+
+void testReadFileToStringBuffer(v8::Handle<v8::Context> context) {
+    LOGD("testReadFileToStringBuffer E:");
+    v8::HandleScope handle_scope;
+
+    v8::TryCatch try_catch;
+    try_catch.SetVerbose(true);
+
+    runJs(context, &try_catch, "local-string",
+        "fileContents = readFileToString(\"mock_ril.js\");\n"
+        "print(\"fileContents:\\n\" + fileContents);\n"
+        "buffer = readFileToBuffer(\"ril.desc\");\n"
+        "print(\"buffer.length=\" + buffer.length);\n");
+    LOGD("testReadFileToStringBuffer X:");
+}
+
+void testJsSupport(v8::Handle<v8::Context> context) {
+    LOGD("testJsSupport E: ********");
+    testRadioState(context);
+    testMsSleep(context);
+    testPrint(context);
+    testCompileError(context);
+    testRuntimeError(context);
+    testReadFile();
+    testReadFileToStringBuffer(context);
+    LOGD("testJsSupport X: ********\n");
+}