Pages

Monday, February 16, 2015

Musings on libnodejs (or libiojs) on Android

What can you do with nodejs on android?

Here are some examples:

  • Run your own server in nodejs on your android device, using the same code you would use for a nodejs x86/x86_64 back end! (e.g. udp/tcp/ip, http, websocket, bit/webtorrent server, webrtc client/STUN/TURN/ICE server);
  • Use existing libraries and code for nodejs and run them in your pocket; (which reminds me NPM (not-paid monkey) is on my TODO list)
  • Connect to other android devices running nodejs;
  • Run nodejs on wearables (ehhh... run a server on your watch?);
  • Use the same javascript client code for testing/production on android;
  • Connect to android sensors/instruments/services via unix domain sockets. (e.g. bluetooth);
  • Connect nodejs with android.webkit.WebView and recreate cordoba/phonegap (wretch);
    • Run cordova-cli on your android device directly;
    • Create stunningly fast mockups with (local) back end code in nodejs
I feel that my hobby/job is coming to full circle, I started out coding in C/C++/javascript/java at the uni. Now I'm still coding in the same languages, but with one more in the mix, Xtend(lang).

I'll clean up my code and release a POC (piece of crap) on the android app store.

Friday, February 13, 2015

Progress report: nodejs / iojs on android

I set out to embed node in an android application and I have succeeded in doing so. It's not an earth-shattering accomplishment, but I'm happy all the same.

I'm exploring ways of passing state between an embedded nodejs instance on android and an android zygote process, via unix domain sockets and http sockets. If the unix domain socket method works, then JNI calls to pass state to and fro can be eliminated completely, except for setting up a nodejs instance.

I managed to build shared libraries and executables for arm-android using either libnodejs.so and libiojs.so. I can load it using an activity-bound sticky android.app.Service and load an http-stream repl script.

I documented how I got there here.

Also, see this commit on how to build the shared lib.

I have a working http-stream REPL via an android device's localhost:8000. Any machine can connect to it.

I'm currently working on a way to expose a node CLI/REPL to the user using android.widget.{EditText, TextView} combined with an android domain socket REPL.

After experimenting with node's domain socket server creating abilities on x86-linux and arm-android, I came to the conclusion that android.net.LocalSocket and nodejs domain socket server will not play nice with each other.

After a lot of pacing and some hair-loss, I realized that I have to determine whether bionic is being called properly by libnodejs (on android).

Right now I have two options:
  • Determine that node's C++ code is calling bionic properly to create a domain socket;
  • turn it around: let android create a android.net.LocalServerSocket, let node connect bind/connect with a domain socket client and start the REPL on the client. I'll have to see if this even works on x86-linux.
I also put some effort into stdio redirection, in the hope that the built-in REPL in nodejs would kick in, but that sort of magical thinking usually leads to nowhere, and it didn't.

Update 14-feb-2015:

Next step: fix libuv; I suspect that pipe.c is not properly coded for android; I suspect that android.net.Local bind/connect fails due to a bad addrlen. According to the code in Pro Android with the NDK page 267-268, a socket that is not in the linux abstract namespace and its addrlen must comply to certain rules, the most important rule is the address length.

Update (same day):

Inserted #if defined(__ANDROID__) ... statements to pipe.c and reused libcutils code instead of libuv socket code, that is shared with android.net.Local(Server)Socket's native methods.

Still not connecting.

Update 16-02-2015:

Mission accomplished. My modified libuv can connect with android.net.LocalSocket over a filesystem-based domain unix socket.

In theory my modification supports abstract domain unix sockets, but I don't know if libuv even supports this.

This means that I have IPC over domain sockets on android, between the main thread and the thread running nodejs.

I have tcp/udp/unix domain socket communication, between android and nodejs!

Woohoo!