Saturday, August 01, 2009

Return of Ruboto!

It's been a while since I was able to work on JRuby's Android support, but tonight I managed to finally circle back. And I've got something much more impressive working today: a real IRB application!



(And yes, this works just fine on the phone too)

It turned out to be incredibly easy to get this working. I'm not using any stinking plugin because they all seemed to just get in my way. So I generated a dummy application using the "android" tool, dropped the jruby jar in "libs", wrote up a quick interactive console, built and signed it, and that's all there was to it.

JRuby turns out to work very well for this sort of thing because we have an interpreter, so we can parse and execute code dynamically. Hooray for interpreted support!

I had to tweak a couple things to work around shortcomings in Android:

  • I had to edit the dx tool to allow up to a 1024M heap, since JRuby's jar has a ton of stuff in it
  • I had to catch and swallow an ArrayIndexOutOfBounds exception coming out of Dalvik's enum support. Bug!
This is of course a proof-of-concept. Writing full applications in Ruby isn't far behind, but we'll need a couple adjustments to JRuby to support it well:
  • Ability to run 100% precompiled with no runtime code generation
  • Strip out parser, interpreter, compiler, and bytecode-generation bits to shrink the jar
  • Tidy up the AOT compiler and wire it into the app build process
  • Generate some Ruby stub logic for the Android APIs, so they'll work well from Ruby
  • Strip down the weirder and wilder Ruby features (eval, etc) to allow fastest-possible execution
I know how to do all of this.

I've pushed ruboto-irb to Github so you can check it out and play with it. I welcome contributors :)

Ruboto lives!

Update: Good news, everyone!

First, the two bugs I've encountered have both been previously reported and are due to be fixed in an upcoming Android release. They are the enum bug and the reflection bug.

Second, someone going by the handle of "Psycho" reports in the comments that the next version of the Android Scripting Environment (ASE) will include JRuby support! Of course I'm interested in more than just scripting applications with JRuby...I'd like to be able to write applications using only Ruby code, so I'll continue working on this. But JRuby support seems to be coming in from all directions.

29 comments:

Ben Atkin said...

This is great news! I could have used this today, when I was at a coffee shop without my laptop computer and wanted to try something out. I used ConnectBot to connect to my slice so I could run irb there, but the connection was slow and I wound up just giving up. From now on I won't have to worry about connectivity just to process a string.

Charles Oliver Nutter said...

Ben: Yeah, once I work out the logistics of doing so I'll release a "JRuby IRB" app to the market for anyone to download and install. The other milestones will come in time.

Makoto said...

Hi.
I am the one who asked about Jruby On Android progress at Rails Underground, and glad to hear the progress.
Since I asked, I am more than happy to become guinea pig.

I got your code from github and tried to set it up, but got various warning and error message.

http://gist.github.com/160040

Could you let me know if I did anything wrong (I don't know much about Java, so might be doing some fundamentally wrong)?

Thanks.

Makoto

Bob said...

Have you looked at the Android Scripting Environment? It might have some reusable scaffolding (for the UI or adapter code, for example).

Where was the bug in enum? Mea culpa.

Nate said...

This is awesome!

You should definitely charge a few bucks for this app. Just releasing it is a huge enough service that most of us would feel guilty using it for free.

Elliott Hughes said...

Have you reported the enum bug?

Charles Oliver Nutter said...

makoto: Using the ruboto-irb project, you do not need/want to pre-dex the jruby.jar file. Leave it as-is, and edit ANDROID_HOME/platforms/android-1.5/tools/dx uncommenting and editing the javaOpts line to look like this:

javaOpts="-Xmx1024M"

Then proceed from the "ant release" step.

Bob, Elliot: I reported it informally on the android platform mailing lists, but I probably never reported it formally. My original email includes the issues that remain in android 1.5, but I can't seem to find it in the archives. I will endeavor to report the issues I've found today.

Nate: I suppose I could consider charging $1 or $0.50 ...it would be the first money I'll have made directly off JRuby if anyone ever buys it :)

swankjesse said...

It might be a bug in iterating >64 element enums. That's fixed in an upcoming build.

H said...

Paying a bit for your great job on getting Ruby on Android, sure. But that would mean cutting out a large part of us Europeans.

Anyways, good job!

Charles Oliver Nutter said...

swankjesse, Bob, Elliott: I think I found the existing bug report about enums, and it matches what I'm seeing. So at least that one is reported. I'll see about reporting the reflection bug if it's not already there.

Unknown said...

Hi Charles,
the next release of ASE (http://code.google.com/p/android-scripting/) will support JRuby with irb, too.

I wrote the JRuby support last week and encountered only one minor problem (eclipse complained that the jar contained an html file it did not like. I think it was doc/index.html but don't remember and can't access my code right now, will send a patch for build.xml).

BTW, you don't have to patch the dx tool, you can start threads with larger heaps from within an Android application (see the different Thread constructors).

Charles Oliver Nutter said...

Psycho: I'm glad to hear ASE will support JRuby soon. I am more interested in being able to write applications entirely in Ruby than just being able to script applications. Is there any interest in this on the Android team?

I would love to hear more about your work, so hopefully you'll post something to the JRuby dev list and we can talk about how to do even more with JRuby on Android.

Ilya Grigorik said...

Awesome! I really need to get myself one of these Android phones.

Makoto said...

Hi, Charles.

Thank you for your advice. I tried your suggestion and it's working on my device!!

http://snurl.com/ok7v8

Took about 5 sec to load up and crashed once, but still it's great achievement. Looking forward to code full Android app in Jruby.

Martin Sadler said...

Very nice! I've followed the instructions and almost there I think.

Last command is currently failing:

adb -s HT93BKV00445 install -r bin/IRB-unsigned.apk
635 KB/s (3453738 bytes in 5.305s)
pkg: /data/local/tmp/IRB-unsigned.apk
Failure [INSTALL_FAILED_DEXOPT]

Any ideas? I've googled and it suggests a validation error or not enough storage. I've got over 1GB free on the card so that shouldn't be a problem?

Charles Oliver Nutter said...

Martin Sadler: Ahh interesting! Since you say there should be plenty of space, then it's likely the other alternative: failure to verify. Maybe you should contact me directly (or on JRuby mailing lists) but check:

* That your device is running Android 1.5
* That your device has enough RAM...not too many apps running when you try to install

Barring that we could try a clean build of the jruby jar and then try some debugging flags to get more information about why it's failing to validate.

Makoto said...

Hi, Martin

Here is the full output when I tried.

http://gist.github.com/160416

NOTE: I could not run it on emulator, but probably it's problem on my env, ad I could not run other app on emulator at that time.

Unknown said...

Sussed out the INSTALL_FAILED_DEXOPT ... turns out although I had plenty of SD memory I didn't have enough internal memory free.. so I uninstalled a few apps and all works just fine now :)

Thanks Charles!

James Britt said...

Very cool. I've forked the git repo (http://github.com/Neurogami/ruboto-irb/) and made a few metadata changes to help folks like me you develop at the command line with vi.

In particular I added a bunch of help about running assorted adb commands, and explained about setting up local.properties (since the default copy in the headius repo will fail unless you happen to be headius :) )

I, too, had trouble installing it on my G1 until I removed some other apps. But it works. :)

Charles Oliver Nutter said...

James, Martin: I've basically done no work to strip out stuff from jruby.jar that won't work on the phone, like native libraries, so I know we can shrink it quite a bit. And if we are able to move toward 100% interpreted or 100% precompiled execution modes, there's additional code we can rip out. We also need to look into how Anroid supports installable libraries, so that there could potentially be a single install of JRuby that several applications use. Then the apps can be as small as the ruby code they ship.

James Britt said...

Cutting out the cruft would be a major first step. The app right now is like 9MB. Another thought was to have other apps use services (Intents?) provided by a main JRuby meta-app, so that not every app would need the jruby jar. I have no actual idea how that would happen (aside from some sort of drb/eval process, which feels unrobust).

That this works at all, though, is quite slick.

Charles Oliver Nutter said...

James: wow, 9MB? Maybe you're doing it with the complete jar? With the normal jruby jar in my build the .apk is only 3.4MB.

I think a good MB or more of that is probably native libs, and there's other stuff we can rip out that won't work on the device (or doesn't make sense on the device) like the Jay yacc debugger, readline, unix sockets, etc. If we could build a stub generator for Java classes you want to call from Ruby, we could eliminate the use of reflection. And of course if we simplify Java integration it would probably be half as much code. There's a lot of room to improve...

James Britt said...

"James: wow, 9MB? Maybe you're doing it with the complete jar? With the normal jruby jar in my build the .apk is only 3.4MB."

On local disk it shows as 3.4, but when I look on my G1, under Manage Applications, it shows it as 9.24. The next largest app there is the browser, at 4.4MB.

So it expands. :)

Unknown said...

Hi Charles,

I published the notes on ASE with JRuby
on my blog.

Roger Pack said...

when you say "Ability to run 100% precompiled with no runtime code generation" you don't mean uninterpreted, I assume?

Charles Oliver Nutter said...

Roger Pack: I mean being able to precompile everything so it all runs full speed. It's not possible (or at least not easy) to generate bytecode on the device itself, so JRuby's normal JIT operation does not work. Precompiling will allow compiling everything in advance.

cartouches d encre said...

Thanks for sharing such nice piece here. I would like to buy it as if I will have no laptop at outside so I can use this one. It will also entertain me. So Thanks for sharing its nice information here. It inspires me to buy it.

Unknown said...

Is it possible to bundle a gem or ruby files with this app? If so, how can it be done?

Regards,
Oliver

Charles Oliver Nutter said...

okeiss: Yes, it's certainly possible! When packaging gems in any JRuby app, you generally want to unpack or bundle them, probably using the new "bundler" library. RubyGems itself does not take well to running inside an archive. Bundling the files should make them "just work" without issue.