Android as a Slave

140 views
Skip to first unread message

Gardner!!

unread,
Aug 10, 2011, 6:22:12 PM8/10/11
to Jenkins Developers
Hello,
I am tasked with testing our code across a growing number of real
Android devices. During my discovery process I converted the slave jar
into Dalvik byte code using the dex tool. I then included this jar in
a regular Android application that I had created using Eclipse. But I
ran into trouble when the Slave jar attempted to load remote classes
from the master. I have scratched up a wiki document with a few links
to information related to getting this working.
https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Slave+on+DalvikVM+in+Android

I guess the next logical step is to start the custom ClassLoader.
Would anyone else be interested in this?

Thanks,
Gardner

Gardner!!

unread,
Aug 10, 2011, 6:39:54 PM8/10/11
to Jenkins Developers
I can't seem to find RemoteClassLoader.java in master on github. I am
looking for something like this:
https://github.com/hudson/hudson/blob/2644cc7a80ff6467dc0d546d26c23c2f28240b7d/hudson-remoting/src/main/java/hudson/remoting/RemoteClassLoader.java

On Aug 10, 3:22 pm, "Gardner!!" <gbickf...@gmail.com> wrote:
> Hello,
>   I am tasked with testing our code across a growing number of real
> Android devices. During my discovery process I converted the slave jar
> into Dalvik byte code using the dex tool. I then included this jar in
> a regular Android application that I had created using Eclipse. But I
> ran into trouble when the Slave jar attempted to load remote classes
> from the master. I have scratched up a wiki document with a few links
> to information related to getting this working.https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Slave+on+DalvikVM...

Kohsuke Kawaguchi

unread,
Aug 10, 2011, 6:58:47 PM8/10/11
to jenkin...@googlegroups.com

Kohsuke Kawaguchi

unread,
Aug 10, 2011, 7:10:35 PM8/10/11
to jenkin...@googlegroups.com
This is awesome!

At runtime, master has all the jars that constitute the Jenkins code
(including all the plugins deployed), so it's relatively easy to
convert each jar file to a dex file and copy it over the wire to
Dalvik. This assumes that Dalvik is resource-rich enough to be able to
load them all (or smart enough to only load classes that are actually
used), but it seems like the good first step to shoot for.

How do you programmatically load a dex file into running Dalvik VM?
Does it use the same java.lang.ClassLoader, or does it have another
class that does it?

2011/8/10 Gardner!! <gbic...@gmail.com>:

--
Kohsuke Kawaguchi

Gardner!!

unread,
Aug 11, 2011, 12:34:50 AM8/11/11
to Jenkins Developers
I am very excited about this as well. It would be possible to reduce
the complexity of our testing system 3 fold.

Initially I was focused very much so on the client ClassLoader
implementation (that runs on the Android device in the slave.jar). By
modifying the RemoteClassLoader to check for java.vm.name == "Dalvik"
and adding the code directly to the RemoteClassLoader we could allow
for _any_ class to be fed into the Slave jar that is running on the
Android device to be converted by the dex tool, on the Android device,
in a procrastinated manner. The problem with procrastination is that
it causes work work to be duplicated always and forever. In this case
the work is being delegated and duplicated to and on an already
overloaded micro-platform.

Given this, It may be acceptable to dex _every_ jar if an "Android
Client Plugin" is installed. This would bloat the client jar for ALL
platforms but would exponentially reduce the work load that is pushed
to Android clients over time. That being the case, what needs to
happen now is a discovery of how extra slave jars/classes are
maintained and a test of dexing all of them and then using the
existing RemoteClassLoader that all slave jars use to get on par with
the master to load the dexed jars from the existing slave jar.

Kohsuke, can you give any insight to where these classes are stored
and marked as being "required" for the slave to have?

Thanks,
Gardner

On Aug 10, 4:10 pm, Kohsuke Kawaguchi <k...@kohsuke.org> wrote:
> This is awesome!
>
> At runtime, master has all the jars that constitute the Jenkins code
> (including all the plugins deployed), so it's relatively easy to
> convert each jar file to a dex file and copy it over the wire to
> Dalvik. This assumes that Dalvik is resource-rich enough to be able to
> load them all (or smart enough to only load classes that are actually
> used), but it seems like the good first step to shoot for.
>
> How do you programmatically load a dex file into running Dalvik VM?
> Does it use the same java.lang.ClassLoader, or does it have another
> class that does it?
>
> 2011/8/10 Gardner!! <gbickf...@gmail.com>:
>
>
>
>
>
>
>
>
>
> > Hello,
> >  I am tasked with testing our code across a growing number of real
> > Android devices. During my discovery process I converted the slave jar
> > into Dalvik byte code using the dex tool. I then included this jar in
> > a regular Android application that I had created using Eclipse. But I
> > ran into trouble when the Slave jar attempted to load remote classes
> > from the master. I have scratched up a wiki document with a few links
> > to information related to getting this working.
> >https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Slave+on+DalvikVM...

John McNair

unread,
Aug 11, 2011, 4:33:24 AM8/11/11
to jenkin...@googlegroups.com
On Wed, Aug 10, 2011 at 6:22 PM, Gardner!! <gbic...@gmail.com> wrote:
 I am tasked with testing our code across a growing number of real
Android devices. During my discovery process I converted the slave jar
into Dalvik byte code using the dex tool. I then included this jar in
a regular Android application that I had created using Eclipse. But I
ran into trouble when the Slave jar attempted to load remote classes
from the master. I have scratched up a wiki document with a few links
to information related to getting this working.
https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Slave+on+DalvikVM+in+Android

+1 for coolness.

--
John McNair
jo...@mcnair.org

Christopher Orr

unread,
Aug 11, 2011, 8:59:26 AM8/11/11
to jenkin...@googlegroups.com
On 11/08/11 00:22, Gardner!! wrote:
> I am tasked with testing our code across a growing number of real
> Android devices. During my discovery process I converted the slave jar
> into Dalvik byte code using the dex tool. I then included this jar in
> a regular Android application that I had created using Eclipse. But I
> ran into trouble when the Slave jar attempted to load remote classes
> from the master. I have scratched up a wiki document with a few links
> to information related to getting this working.
> https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Slave+on+DalvikVM+in+Android

This sounds awesome.

Possibly getting ahead of myself here, but what's your thinking on how
Android slaves would be launched, and how the TCP connection between
slave and master would work?

Regards,
Chris

Gardner!!

unread,
Aug 11, 2011, 7:25:23 PM8/11/11
to Jenkins Developers
Christopher,
The TCP connection would be the same as the existing Slave.jar
(through Channel) which Kohsuke has already written and tested.

The problem with Android applications that run in user space (non-
rooted) is that there is no way to install an application. This
restriction is not so when run as user "shell" which is the uid given
to processes that are launched via ADB. The normal Slave jar could be
downloaded by a host machine that the device is connected to. It is
safe to assume that this host machine has the Android SDK installed to
communicate with the device via ADB. This means that the dex tool is
on the host already as well. The jar can be dexed and pushed to the
device and launched via ADB. This would give the most permissions
possible on production devices.

-g

On Aug 11, 5:59 am, Christopher Orr <ch...@orr.me.uk> wrote:
> On 11/08/11 00:22, Gardner!! wrote:
>
> >    I am tasked with testing our code across a growing number of real
> > Android devices. During my discovery process I converted the slave jar
> > into Dalvik byte code using the dex tool. I then included this jar in
> > a regular Android application that I had created using Eclipse. But I
> > ran into trouble when the Slave jar attempted to load remote classes
> > from the master. I have scratched up a wiki document with a few links
> > to information related to getting this working.
> >https://wiki.jenkins-ci.org/display/JENKINS/Jenkins+Slave+on+DalvikVM...

Gardner!!

unread,
Aug 11, 2011, 10:05:04 PM8/11/11
to Jenkins Developers
I created a sample Android application that is able to convert java
bytecode to Dalvik bytecode using the supplied dex tool. It also
attempts to connect to the master by driving the classes slave.jar.
The code can be got here: https://github.com/gardner/remoting/tree/master/DexTest
(You will need to modify the ip address and secret key in
SlaveService.java)

As you can see from the logcat output below the Channel is reaching an
unexpected EOF. The next step is to load up the server locally in a
debugger and see what I can find.

08-11 18:48:46.644 14830 14838 I DexTest : Connecting to
10.0.2.2:43987
08-11 18:48:46.652 14830 14838 I DexTest : Handshaking
08-11 18:48:46.793 14830 14838 I DexTest : Connected
08-11 18:48:47.277 14830 14841 E dalvikvm: ERROR:
defineClass(0x4055e908, hudson.slaves.SlaveComputer$SlaveVersion,
0x405815f8, 0, 1141, 0x0)
08-11 18:48:47.285 14830 14841 W dalvikvm: Exception Ljava/lang/
NullPointerException; thrown while initializing Lhudson/remoting/
RemoteClassLoader$ClassLoaderProxy;
08-11 18:48:47.386 14830 14840 E hudson.remoting.Channel: I/O error in
channel channel
08-11 18:48:47.386 14830 14840 E hudson.remoting.Channel:
java.io.IOException: Unexpected termination of the channel
08-11 18:48:47.386 14830 14840 E hudson.remoting.Channel: at
hudson.remoting.Channel$ReaderThread.run(Channel.java:998)
08-11 18:48:47.386 14830 14840 E hudson.remoting.Channel: Caused by:
java.io.EOFException
08-11 18:48:47.386 14830 14840 E hudson.remoting.Channel: at
java.io.DataInputStream.readByte(DataInputStream.java:131)
08-11 18:48:47.386 14830 14840 E hudson.remoting.Channel: at
java.io.ObjectInputStream.nextTC(ObjectInputStream.java:628)
08-11 18:48:47.386 14830 14840 E hudson.remoting.Channel: at
java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:
907)
08-11 18:48:47.386 14830 14840 E hudson.remoting.Channel: at
java.io.ObjectInputStream.readObject(ObjectInputStream.java:2262)
08-11 18:48:47.386 14830 14840 E hudson.remoting.Channel: at
java.io.ObjectInputStream.readObject(ObjectInputStream.java:2217)
08-11 18:48:47.386 14830 14840 E hudson.remoting.Channel: at
hudson.remoting.Channel$ReaderThread.run(Channel.java:992)
08-11 18:48:47.386 14830 14838 I DexTest : Terminated
08-11 18:48:47.386 14830 14838 I DexTest : Client jar disconnected.

Kohsuke Kawaguchi

unread,
Aug 12, 2011, 12:09:35 AM8/12/11
to jenkin...@googlegroups.com, Gardner!!
On 08/10/2011 09:34 PM, Gardner!! wrote:
> I am very excited about this as well. It would be possible to reduce
> the complexity of our testing system 3 fold.
>
> Initially I was focused very much so on the client ClassLoader
> implementation (that runs on the Android device in the slave.jar). By
> modifying the RemoteClassLoader to check for java.vm.name == "Dalvik"
> and adding the code directly to the RemoteClassLoader we could allow
> for _any_ class to be fed into the Slave jar that is running on the
> Android device to be converted by the dex tool, on the Android device,
> in a procrastinated manner. The problem with procrastination is that
> it causes work work to be duplicated always and forever. In this case
> the work is being delegated and duplicated to and on an already
> overloaded micro-platform.

I was under the assumption that a jar file is a minimum unit of
conversion, not a class file, and hence my suggestion. But I think you
are saying that is not the case.

(OTOH, when I look at the DexClassLoader and DexFile source code, it
seems to me that my assumption is correct, and if we create one dex per
one class, I'm not sure if Dalvik can cope with that many DEX files.)

If "one class at a time" lazy conversion is possible, I think that's a
very good starting point. For one, that's how all the slaves work, and
it can be iteratively improved from there, for example to push the
conversion to the server, or cache the result.

Do you have some code that shows how to convert one class and load it
into Android? Some kind of PoC/sandbox that lets other people (including
me) to kick the tire?


> Given this, It may be acceptable to dex _every_ jar if an "Android
> Client Plugin" is installed. This would bloat the client jar for ALL
> platforms but would exponentially reduce the work load that is pushed
> to Android clients over time.

Yes. Or a fairly straight-forward optimization from there is to
translate a regular jar to a dexed jar on the fly (with some kind of
caching) if we know we are talking to Android slave.

> That being the case, what needs to
> happen now is a discovery of how extra slave jars/classes are
> maintained and a test of dexing all of them and then using the
> existing RemoteClassLoader that all slave jars use to get on par with
> the master to load the dexed jars from the existing slave jar.

The general workflow in the current RemoteClassLoader implementation is:

1. slave tries to load "a.b.c.Foo" class
2. RemoteClassLoader requests the master to send it the byte[]
for a/b/c/Foo.class
3. master sends it to the client
4. slave injects that into VM via ClassLoader.defineClass

so the whole scheme doesn't involve the notion of jar file at all.

For Android slaves, the workflow needs to be:

1. slave tries to load "a.b.c.Foo" class
2. RemoteClassLoader requests the master to send the
jar file that contains a.b.c.Foo
3. master creates a dex file for the jar
4. byte[] gets sent
4. slave opens this dex file via DexFile and loads the class


> Kohsuke, can you give any insight to where these classes are stored
> and marked as being "required" for the slave to have?

I've pushed 'dalvik-server' and 'dalvik-client' branches in
http://github.com/jenkinsci/remoting

They contain the pseudo-code that I think will make it work. The reason
there are two branches, as opposed to one, is simply because I was lazy;
the client side that runs on Dalvik needs to use some Dalvik-specific
classes, so that portion needs to be isolated somewhat so that it won't
cause UnsatisfiedLinkError when run on JavaVM.

I'll leave that exercise to you :-)


I think it'll be also easier to create a small stand-alone JavaSE
program that initiates the channel pair, as opposed to do this
experiment with full-blown Jenkins.


--
Kohsuke Kawaguchi | CloudBees, Inc. | http://cloudbees.com/

Gardner!!

unread,
Aug 13, 2011, 3:59:32 AM8/13/11
to Jenkins Developers
This is really helpful! I am going to work with dalvik-server first
because it seems to be the most sensible long-term approach. I'll
submit a pull request when I have it working! :)

-g

On Aug 11, 9:09 pm, Kohsuke Kawaguchi <kkawagu...@cloudbees.com>
wrote:
> I've pushed 'dalvik-server' and 'dalvik-client' branches inhttp://github.com/jenkinsci/remoting

黎 汪

unread,
Nov 6, 2012, 3:27:12 AM11/6/12
to jenkin...@googlegroups.com, gbic...@gmail.com
i'm  asked to do the same thing~. so i'm wondering if you have already stopped working on this issue

linards...@gmail.com

unread,
Nov 6, 2012, 8:07:12 AM11/6/12
to jenkin...@googlegroups.com, gbic...@gmail.com

I highly doubt it will be a good idea because current Jenkins slave implementation is very buggy. First fix the issues, then invent bicycle on three weels...

Reply all
Reply to author
Forward
0 new messages