+---------------+ +------------+ | +-----------> | | Android Phone| |Laptop | | <-----------+ | +---------------+ +------------+
+---------------+ +------------+ | +-----------> | |FirefoxOS Phone| |Laptop | | <-----------+ | +---------------+ +------------+
+-----------------+ +------------------+ | | adb is running | | | | | | | $ adb devices +--------------->|full_unagi device| | |IPC with sockets| | | | | | +--------+--------+ +--------------^---+ | | | |IPC with sockets | adb not running | | +-------------------------+ | | | Fork a subprocess | | +----->| (2 seconds of sleeping) +-------+ | | +-------------------------+
It's not ideal
$ git clone https://android.googlesource.com/platform/system/core
Foreign-function interface to C from JavaScript
let { Cu } = require('chrome');
Cu.import("resources://gre/modules/ctypes.jsm");
let lib = ctypes.open("some_lib.so");
let some_function = lib.declare("some_function",
default_abi,
ctypes.int,
ctypes.char.ptr);
let x = some_function("just some string");
Small wrapper I made for declaring functions
let lib = ctypes.open("some_lib.so");
I.declare({ name: "some_function",
returns: ctypes.int,
args: [ ctypes.char.ptr ]
}, lib);
... /* later in the code */
let some_function = I.use("some_function");
some_function("just some string");
Avoids globals and has easy-to-remember syntaxIt's complicated (call a function with a C function pointer)
/* C code */
DLL_EXPORT void long_task(void (*callback)(char *)) {
char * the_answer = something_long();
callback(the_answer);
}
/* JS code */
let CallbackType = ctypes.FunctionType(ctypes.default_abi,
ctypes.int,
[ ctypes.char.ptr ]);
let long_task = I.declare({ name: "long_task",
returns: ctypes.void_t,
args: [ CallbackType.ptr ]
}, lib);
let callbackFn = function(str) { console.log("in JS", str.readString()); };
long_task( CallbackType.ptr(callbackFn) );
It's worse in the real codeFix?
/* C code */
void long_task() {
struct a_message {
char * str;
};
struct a_message m = { something_long() }; void * res;
MSG(&res, "achannel", m);
}
/* JS code */
let jsMsgFn = function(channel, args) {
switch(channel.readString()) {
case "achannel":
let [ x ] = JsMessage.unpack(args, ctypes.char.ptr);
return JsMessage.pack(11, Number);
}
};
Use MSG macro to avoid modifying much native code
ADB calls exit(1)
for minor errors
exit(1)
to quit in every code path
exit(1)
crashes Firefox
+ 38,104 additions
- 804 deletions
Before
+------------+ +----------------+ | PHONE | | COMPUTER | | | Platform-specific | +------------+ | | +--------+ | drivers | | adb daemon | | | | adbd |+--------------------->| process | | | | |<---------------------++-^+---------+ | | +--------+ | USB | || | +------------+ | || SOCKETS | | || | | || | | || | | +-+v---------+ | | | adb client | | | | process | | | | | | | | | | | | | | | +------------+ | | | +----------------+
After
+------------+ +----------------+ | PHONE | | COMPUTER | | | Platform-specific | +------------+ | | +--------+ | drivers | | | | | | adbd |+--------------------->| Simulator | | | | |<---------------------+| Add-on | | | +--------+ | USB | | in | | +------------+ | | Firefox | | | | process | | | | | | | | | | | +------------+ | | | +----------------+
/* C code */
int fd = _adb_connect("shell:ls");
/* JS code */
let output = readFully(fd);
console.log(output);
int fd
just like on UnixWorkers Per phone UI Server Device Loop Input Output JS:Simulator starts ADB + | +--------->JS:Set up code + | | (really C to JS to UI to new worker to C) v C:server_thread+-->C:Start device + loop | (look for devices) v C:fdevent_loop + | on new device JS:device tracker<-------++------------------------------> C:Write to device | +--------------------------------------------->C:Read
from device