+---------------+ +------------+
| +-----------> |
| 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