2 * Copyright (C) 2010 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
20 #include "ctrl_server.h"
22 #include "node_buffer.h"
23 #include "node_object_wrap.h"
24 #include "node_util.h"
25 #include "protobuf_v8.h"
26 #include "responses.h"
30 #include "worker_v8.h"
32 #include "js_support.h"
34 //#define JS_SUPPORT_DEBUG
35 #ifdef JS_SUPPORT_DEBUG
37 #define DBG(...) ALOGD(__VA_ARGS__)
48 RIL_RadioState gRadioState = RADIO_STATE_UNAVAILABLE;
50 v8::Handle<v8::Value> RadioStateGetter(v8::Local<v8::String> property,
51 const v8::AccessorInfo& info) {
52 return v8::Integer::New((int)gRadioState);
55 void RadioStateSetter(v8::Local<v8::String> property,
56 v8::Local<v8::Value> value, const v8::AccessorInfo& info) {
57 gRadioState = RIL_RadioState(value->Int32Value());
60 // A javascript sleep for a number of milli-seconds
61 v8::Handle<v8::Value> MsSleep(const v8::Arguments& args) {
62 if (args.Length() != 1) {
63 DBG("MsSleep: expecting milli-seconds to sleep");
65 v8::Handle<v8::Value> v8MsValue(args[0]->ToObject());
66 int ms = int(v8MsValue->NumberValue());
67 v8::Unlocker unlocker;
71 return v8::Undefined();
74 // A javascript print function
75 v8::Handle<v8::Value> Print(const v8::Arguments& args) {
77 const int str_size = 1000;
78 char* str = new char[str_size];
80 for (int i = 0; i < args.Length(); i++) {
81 v8::HandleScope handle_scope;
85 offset += snprintf(&str[offset], str_size, " ");
87 v8::String::Utf8Value strUtf8(args[i]);
88 const char* cstr = ToCString(strUtf8);
89 offset += snprintf(&str[offset], str_size, "%s", cstr);
93 return v8::Undefined();
96 int ReadFile(const char *fileName, char** data, size_t *length) {
99 size_t fileLength = 0;
102 DBG("ReadFile E fileName=%s", fileName);
104 f = fopen(fileName, "rb");
106 DBG("Could not fopen '%s'", fileName);
107 status = STATUS_COULD_NOT_OPEN_FILE;
109 // Determine the length of the file
110 fseek(f, 0, SEEK_END);
111 fileLength = ftell(f);
112 DBG("fileLength=%d", fileLength);
115 // Read file into a buffer
116 buffer = new char[fileLength+1];
117 size_t readLength = fread(buffer, 1, fileLength, f);
118 if (readLength != fileLength) {
119 DBG("Couldn't read entire file");
122 status = STATUS_COULD_NOT_READ_FILE;
125 buffer[fileLength] = 0;
131 if (length != NULL) {
132 *length = fileLength;
135 DBG("ReadFile X status=%d", status);
139 char *CreateFileName(const v8::Arguments& args) {
140 v8::String::Utf8Value fileNameUtf8Value(args[0]);
141 const char* fileName = ToCString(fileNameUtf8Value);
142 const char* directory = "/sdcard/data/";
144 int fullPathLength = strlen(directory) + strlen(fileName) + 1;
145 char * fullPath = new char[fullPathLength];
146 strncpy(fullPath, directory, fullPathLength);
147 strncat(fullPath, fileName, fullPathLength);
151 // A javascript read file function arg[0] = filename
152 v8::Handle<v8::Value> ReadFileToString(const v8::Arguments& args) {
153 DBG("ReadFileToString E");
154 v8::HandleScope handle_scope;
155 v8::Handle<v8::Value> retValue;
157 if (args.Length() < 1) {
158 // No file name return Undefined
159 DBG("ReadFile X no argumens");
160 return v8::Undefined();
162 char *fileName = CreateFileName(args);
165 int status = ReadFile(fileName, &buffer);
167 retValue = v8::String::New(buffer);
169 retValue = v8::Undefined();
172 DBG("ReadFileToString X");
176 // A javascript read file function arg[0] = filename
177 v8::Handle<v8::Value> ReadFileToBuffer(const v8::Arguments& args) {
178 DBG("ReadFileToBuffer E");
179 v8::HandleScope handle_scope;
180 v8::Handle<v8::Value> retValue;
182 if (args.Length() < 1) {
183 // No file name return Undefined
184 DBG("ReadFileToBuffer X no argumens");
185 return v8::Undefined();
187 char *fileName = CreateFileName(args);
191 int status = ReadFile(fileName, &buffer, &length);
193 Buffer *buf = Buffer::New(length);
194 memmove(buf->data(), buffer, length);
195 retValue = buf->handle_;
197 retValue = v8::Undefined();
200 DBG("ReadFileToBuffer X");
204 void ErrorCallback(v8::Handle<v8::Message> message,
205 v8::Handle<v8::Value> data) {
206 LogErrorMessage(message, "");
209 // Read, compile and run a javascript file
210 v8::Handle<v8::Value> Include(const v8::Arguments& args) {
212 v8::HandleScope handle_scope;
213 v8::Handle<v8::Value> retValue;
214 v8::TryCatch try_catch;
215 try_catch.SetVerbose(true);
217 if (args.Length() < 1) {
218 // No file name return Undefined
219 DBG("Include X no argumens");
220 return v8::Undefined();
222 char *fileName = CreateFileName(args);
225 int status = ReadFile(fileName, &buffer);
227 runJs(v8::Context::GetCurrent(), &try_catch, fileName, buffer);
229 retValue = v8::Undefined();
238 * Create a JsContext, must be called within a HandleScope?
240 v8::Persistent<v8::Context> makeJsContext() {
241 v8::HandleScope handle_scope;
242 v8::TryCatch try_catch;
244 // Add a Message listner to Catch errors as they occur
245 v8::V8::AddMessageListener(ErrorCallback);
247 // Create a template for the global object and
248 // add the function template for print to it.
249 v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New();
250 global->SetAccessor(v8::String::New("gRadioState"),
251 RadioStateGetter, RadioStateSetter);
252 global->Set(v8::String::New("msSleep"), v8::FunctionTemplate::New(MsSleep));
253 global->Set(v8::String::New("print"), v8::FunctionTemplate::New(Print));
254 global->Set(v8::String::New("readFileToBuffer"),
255 v8::FunctionTemplate::New(ReadFileToBuffer));
256 global->Set(v8::String::New("readFileToString"),
257 v8::FunctionTemplate::New(ReadFileToString));
258 global->Set(v8::String::New("sendRilRequestComplete"),
259 v8::FunctionTemplate::New(SendRilRequestComplete));
260 global->Set(v8::String::New("sendRilUnsolicitedResponse"),
261 v8::FunctionTemplate::New(SendRilUnsolicitedResponse));
262 global->Set(v8::String::New("sendCtrlRequestComplete"),
263 v8::FunctionTemplate::New(SendCtrlRequestComplete));
264 global->Set(v8::String::New("include"), v8::FunctionTemplate::New(Include));
265 WorkerV8ObjectTemplateInit(global);
266 SchemaObjectTemplateInit(global);
267 Buffer::InitializeObjectTemplate(global);
269 // Create context with our globals and make it the current scope
270 v8::Persistent<v8::Context> context = v8::Context::New(NULL, global);
273 if (try_catch.HasCaught()) {
274 DBG("makeJsContext: Exception making the context");
275 ReportException(&try_catch);
283 * Run some javascript code.
285 void runJs(v8::Handle<v8::Context> context, v8::TryCatch *try_catch,
286 const char *fileName, const char *code) {
287 v8::HandleScope handle_scope;
289 // Compile the source
290 v8::Handle<v8::Script> script = v8::Script::Compile(
291 v8::String::New(code), v8::String::New(fileName));
292 if (try_catch->HasCaught()) {
293 ALOGE("-- Compiling the source failed");
295 // Run the resulting script
296 v8::Handle<v8::Value> result = script->Run();
297 if (try_catch->HasCaught()) {
298 ALOGE("-- Running the script failed");
303 void testRadioState(v8::Handle<v8::Context> context) {
304 ALOGD("testRadioState E:");
305 v8::HandleScope handle_scope;
307 v8::TryCatch try_catch;
308 try_catch.SetVerbose(true);
310 runJs(context, &try_catch, "local-string",
311 "for(i = 0; i < 10; i++) {\n"
312 " gRadioState = i;\n"
313 " print('gRadioState=' + gRadioState);\n"
316 "print('last gRadioState=' + gRadioState);\n");
317 ALOGD("testRadioState X:");
320 void testMsSleep(v8::Handle<v8::Context> context) {
321 ALOGD("testMsSleep E:");
322 v8::HandleScope handle_scope;
324 v8::TryCatch try_catch;
325 try_catch.SetVerbose(true);
327 runJs(context, &try_catch, "local-string",
328 "for(i = 0; i < 10; i++) {\n"
329 " sleeptime = i * 200\n"
330 " print('msSleep ' + sleeptime);\n"
331 " msSleep(sleeptime);\n"
333 ALOGD("testMsSleep X:");
336 void testPrint(v8::Handle<v8::Context> context) {
337 ALOGD("testPrint E:");
338 v8::HandleScope handle_scope;
340 v8::TryCatch try_catch;
341 try_catch.SetVerbose(true);
343 runJs(context, &try_catch, "local-string", "print(\"Hello\")");
344 ALOGD("testPrint X:");
347 void testCompileError(v8::Handle<v8::Context> context) {
348 ALOGD("testCompileError E:");
349 v8::HandleScope handle_scope;
351 v8::TryCatch try_catch;
352 try_catch.SetVerbose(true);
354 // +++ generate a compile time error
355 runJs(context, &try_catch, "local-string", "+++");
356 ALOGD("testCompileError X:");
359 void testRuntimeError(v8::Handle<v8::Context> context) {
360 ALOGD("testRuntimeError E:");
361 v8::HandleScope handle_scope;
363 v8::TryCatch try_catch;
364 try_catch.SetVerbose(true);
367 runJs(context, &try_catch, "local-string",
368 "function hello() {\n"
369 " print(\"Hi there\");\n"
372 ALOGD("testRuntimeError X:");
375 void testReadFile() {
380 ALOGD("testReadFile E:");
382 status = ReadFile("/sdcard/data/no-file", &buffer, &length);
383 ALOGD("testReadFile expect status != 0, status=%d, buffer=%p, length=%d",
384 status, buffer, length);
386 ALOGD("testReadFile X:");
390 void testReadFileToStringBuffer(v8::Handle<v8::Context> context) {
391 ALOGD("testReadFileToStringBuffer E:");
392 v8::HandleScope handle_scope;
394 v8::TryCatch try_catch;
395 try_catch.SetVerbose(true);
397 runJs(context, &try_catch, "local-string",
398 "fileContents = readFileToString(\"mock_ril.js\");\n"
399 "print(\"fileContents:\\n\" + fileContents);\n"
400 "buffer = readFileToBuffer(\"ril.desc\");\n"
401 "print(\"buffer.length=\" + buffer.length);\n");
402 ALOGD("testReadFileToStringBuffer X:");
405 void testJsSupport(v8::Handle<v8::Context> context) {
406 ALOGD("testJsSupport E: ********");
407 testRadioState(context);
408 testMsSleep(context);
410 testCompileError(context);
411 testRuntimeError(context);
413 testReadFileToStringBuffer(context);
414 ALOGD("testJsSupport X: ********\n");