| 1 | = OMF on Android = |
| 2 | |
| 3 | == 0. Setup device == |
| 4 | |
| 5 | In order to run OMF Resource Controller on an Android device, we need a Ruby interpreter. |
| 6 | |
| 7 | We will use [http://code.google.com/p/android-scripting/ Scripting Layer for Android (SL4A).] Go to Downloads and download the latest revision of sl4a.apk. |
| 8 | |
| 9 | You can install this app via adb: |
| 10 | {{{ |
| 11 | adb install sl4a.apk |
| 12 | }}} |
| 13 | or you can copy the file onto your device's SD card and navigate to it with a file manager such as Astro. |
| 14 | |
| 15 | Note: You will need to have enabled installation of non-Market apps via Setting > Applications > Unknown Sources. |
| 16 | |
| 17 | SL4A only includes the Shell interpreter, but we need Ruby functionality. Fortunately, SL4A supports a JRuby interpreter. JRuby is an implementation of Ruby on the Java Virtual Machine. The majority of your code and gems will run properly, with the exception of native gems written in C, such as the built in Yaml parser. |
| 18 | |
| 19 | To install the JRuby interpreter, press Menu and then View > Interpreters. From here you can see all installed interpreters. To add a new one, press Menu and then Add > JRuby. The .apk should automatically download. Install and open it. Press install, and it will download the necessary libraries to start the JRuby interpreter from SL4A. |
| 20 | |
| 21 | == 1. Get OMF source code == |
| 22 | |
| 23 | Now we need the OMF source code to run. |
| 24 | {{{ |
| 25 | git clone git://git.mytestbed.net/omf.git -b release-5.3 |
| 26 | }}} |
| 27 | |
| 28 | We will only work with omf-common and omf-resctl. |
| 29 | |
| 30 | Copy the root directory that holds omf-common and omf-resctl to sl4a/scripts on the device's SD card. You should now be able to view the OMF files in SL4A. |
| 31 | |
| 32 | == 2. Bootstrap OMF == |
| 33 | |
| 34 | If you just try to start the resource controller by running omf-resctl/ruby/omf-resctl/nodeAgent.rb, you will run into errors regarding the load path. This is because the resource controller is supposed to be started via omf-resctl/sbin/omf-resctl: |
| 35 | {{{ |
| 36 | #!/bin/sh |
| 37 | #... |
| 38 | |
| 39 | export LANG=c |
| 40 | |
| 41 | VER=5.3 |
| 42 | APP=omf-resctl/nodeAgent.rb |
| 43 | if [ -e /usr/share/omf-resctl-$VER/$APP ]; then |
| 44 | PDIR=/usr/share/omf-resctl-$VER |
| 45 | else |
| 46 | echo "Cannot find the ruby module location ($APP)." |
| 47 | exit 1; |
| 48 | fi |
| 49 | exec ruby1.8 -I$PDIR -I/usr/share/omf-common-$VER $PDIR/$APP $* |
| 50 | }}} |
| 51 | |
| 52 | So nodeAgent.rb is run with ruby1.8 with the 2 -I flags. These -I flags load the dependencies into Ruby before nodeAgent.rb is run. Since we are working with an app that does not support command line arguments, we will have to implement a workaround. |
| 53 | |
| 54 | In the root directory of the OMF source code, create a file called bootstrap.rb and copy this in: |
| 55 | {{{ |
| 56 | APP_DIR = File.expand_path File.dirname(__FILE__) |
| 57 | #GEM_DIR = File.join(APP_DIR, 'vendor', 'gems') |
| 58 | RESCTL_DIR = File.join(APP_DIR, 'omf-resctl', 'ruby') |
| 59 | COMMON_DIR = File.join(APP_DIR, 'omf-common', 'ruby') |
| 60 | NODE_PATH = File.join(RESCTL_DIR,'omf-resctl', 'nodeAgent.rb') |
| 61 | |
| 62 | #Dir.entries(GEM_DIR).each do |dir| |
| 63 | # $LOAD_PATH << File.join(GEM_DIR, dir, 'lib') |
| 64 | #end |
| 65 | |
| 66 | $LOAD_PATH << RESCTL_DIR |
| 67 | $LOAD_PATH << COMMON_DIR |
| 68 | puts $LOAD_PATH |
| 69 | |
| 70 | puts NODE_PATH |
| 71 | |
| 72 | require NODE_PATH |
| 73 | }}} |
| 74 | |
| 75 | This script is in essence a Ruby translation of the shell script above that loads all Ruby dependencies (RESCTL_DIR and COMMON_DIR) to the LOAD_PATH variable before running nodeAgent.rb (NODE_PATH). |
| 76 | |
| 77 | == 3. Load networking drivers == |
| 78 | |
| 79 | In order to properly retreve data from the device, you need to use the corresponding driver for the wireless chipsets. nodeAgent does this by running lspci, which does not work on Android. |
| 80 | |
| 81 | Comment out the call to lspci from line 412-425 and 428-447 in omf-resctl\ruby\omf-resctl\omf_agent\nodeAgent.rb, leaving the Intel card portion uncommented |
| 82 | {{{ |
| 83 | require 'omf-resctl/omf_driver/intel' |
| 84 | MObject.info "Have Intel cards" |
| 85 | AgentCommands::DEV_MAPPINGS['net/w0'] = IntelDevice.new('net/w0', 'eth2') |
| 86 | AgentCommands::DEV_MAPPINGS['net/w1'] = IntelDevice.new('net/w1', 'eth3') |
| 87 | }}} |
| 88 | |
| 89 | The Intel driver is not completely compatible with the wireless chipsets on the device, but it works. |
| 90 | |
| 91 | == 4. Vendorize Gems == |
| 92 | OMF relies on several gems that we do not have on the SD card. |
| 93 | |
| 94 | In order to continue, we need the log4r, xmpp4r, and RbYAML gems. On a computer with Ruby and RubyGems installed, type |
| 95 | {{{ |
| 96 | gem install log4r |
| 97 | gem install xmpp4r |
| 98 | gem install RbYAML |
| 99 | }}} |
| 100 | to install the gems. SL4A doesnt support RubyGems, so we will have to vendorize them. |
| 101 | {{{ |
| 102 | mkdir vendor/gems |
| 103 | gem unpack log4r --target=vendor/gems |
| 104 | gem unpack xmpp4r --target=vendor/gems |
| 105 | gem unpack RbYAML --target=vendor/gems |
| 106 | }}} |
| 107 | and then place the /vendor directory in the root directory of OMF on the device's SD card. |
| 108 | |
| 109 | Uncomment the 4 lines in bootstrap.rb - They check the vendor/gems folder and manually load the gems. |
| 110 | |
| 111 | OMF uses .yaml configuration files, but the default Yaml parser in Ruby is written in C, and therefore will not work on JRuby. We will use RbYAML instead. Replace line 358-359 of omf-resctl\ruby\omf-resctl\omf_agent\nodeAgent.rb: |
| 112 | {{{ |
| 113 | require 'yaml' |
| 114 | h = YAML::load_file(@configFile) |
| 115 | }}} |
| 116 | with RbYAML: |
| 117 | {{{ |
| 118 | require 'rbyaml' |
| 119 | temp_h = RbYAML::load_file(@configFile) |
| 120 | h = symbolize(temp_h) |
| 121 | }}} |
| 122 | and add the symbolize private method after line 386: |
| 123 | {{{ |
| 124 | def symbolize (hash) |
| 125 | if hash.class == Hash |
| 126 | newHash = {} |
| 127 | hash.each do |k, v| |
| 128 | newHash[k.gsub(":", "").to_sym] = symbolize(v) |
| 129 | end |
| 130 | return newHash |
| 131 | else |
| 132 | return hash |
| 133 | end |
| 134 | end |
| 135 | }}} |
| 136 | This is necessary because the native Yaml parser returns a hash with symbols for keys, and RbYAML returns a hash with strings as keys. We recursively copy the data into a new hash and convert the key from a string to symbol. |
| 137 | |
| 138 | == 5. Configure node == |
| 139 | Resource Controller should be running now, you need to configure it accordingly. |