I had trouble testing xmpp, I created a simple app, txmpp based on the sample code XmppDataMessageSend and couldn’t get it to work. The ServiceConnection call back was never executed.
Turns out you need to run the emulator and go into Dev Tools/XMPP Settings and add a valid gmail account, then it works as expected, see here. This doesn’t seem to allow general peer to peer connections between apps and in particular seems to require all messages to go through a central service. Not what I was looking for:(
Here other people are looking at similar issues and Dan Morrill replies here that Xmpp isn’t intended for adhoc communication and suggests Blue tooth. Interesting that wifi isn’t mentioned?
As of today, Dec 21 here is a short list of <peer to peer> hits when searching the Android-developer list:
Here, here, here, here, …
There was two pages worth.
Here was a question about getting the local IP address, someone wants to do RTP.
I wanted to start eclipse using a different workspace than the default. I searched for <eclipse new workspace> and here it said to use the -data option and so that you know which workspace your in use the showlocatin option:
eclipse –data ws-android –showlocation
I then added -showlocation to the the gnome application lanuch icon.
To install Eclipse you need to install sun-java, the gcj version installed in Ubuntu 7.10 isn’t capable of fully supporting Eclipse. What I did was install sun-java-6-* via synaptic, but of course its not that simple.
I installed all of the sun-java6-* files via synaptic, of course that didn’t install flawlessly as you need to download jdk-6-doc.zip from here selecting download for “Java SE 6 Documentation” which was here (you need to “Accept the license agreement”) and place it in /tmp/. Next I downloaded Eclipse from here and untar’d it into /usr. I then setup a symbolic link from /usr/local/bin/eclipse to /usr/eclipse/eclipse, the I ran ecplise. It boots but said “Error creating the view”. I did a little searching, turns out had the wrong jvm. I needed to uninstall java-gc-compat and create a symbolic link from /etc/alternatives/java to /usr/lib/jvm/java-6-sun/bin/java. Then it finally ran!
The short list of instructions:
*) Download Eclipse I chose “Eclipse Classic 3.3.1.1″.
*) Download jdk-6-doc.zip and place in /tmp/
*) Uninstall java-gcj-compat via synaptic or apt
*) Install all sun-java-6-* via synaptic or apt
*) Besure there is a symbolic link from /etc/alternatives/java -> /usr/lib/jvm/java-6-sun/bin/java
sudo ln -sf /usr/lib/jvm/java-6-sun/bin/java /etc/alternatives/java
*) Untar Eclipse into /usr (creates /usr/eclipse/)
cd /usr
sudo tar -xvf ~/downloads/eclipse-SDK-3.3.1.1-linux-gtk-x86_64.tar.gz
You should now be able to run eclipse and the Welcome screen should appear, if you drop right into Eclipse and a warning that you couldn’t create a view then you’re executing the wrong jvm. Start by using the comand:
wink@ic2d1:$ which java
/usr/bin/java
wink@ic2d1:$ ls -l /usr/bin/java
lrwxrwxrwx 1 root root 22 2007-12-04 09:55 /usr/bin/java -> /etc/alternatives/java
wink@ic2d1:$ ls -l /etc/alternatives/java
lrwxrwxrwx 1 root root 32 2007-12-04 20:59 /etc/alternatives/java -> /usr/lib/jvm/java-6-sun/bin/java
wink@ic2d1:$ ls -l /usr/lib/jvm/java-6-sun/bin/java
lrwxrwxrwx 1 root root 15 2007-12-04 17:53 /usr/lib/jvm/java-6-sun/bin/java -> ../jre/bin/java
wink@ic2d1:$ ls -l /usr/lib/jvm/java-6-sun/jre/bin/java
-rwxr-xr-x 1 root root 50650 2007-09-24 23:34 /usr/lib/jvm/java-6-sun/jre/bin/java
As you can see on my machine there are several links before getting to the actual executable.
For my state machine code I’d like to determine at runtime what states the user has created and what there hierarchy. I’ve created an interface that all states of a state machine must implement. My first thought was to use Annotation, but that didn’t work out, Android doesn’t seem to implement retrieving the annotation at runtime. So today I came up with the idea of using getClasses():
Class cl = this.getClass();
Class classes[] = cl.getClasses();
Log.v(df, “Hsm: Hsm() classes.length=” + classes.length);
for (Class c : classes) {
Log.v(df, “Hsm: class %s”, c.getName());
}
But that doesn’t work either:
I/ ( 587): Client: MyHsm() E name=TestHsmClient0
W/dalvikvm( 587): No implementation found for native java/lang/Class.getDeclaredClasses (Ljava/lang/Class;Z)[Ljava/lang/Class;
D/dalvikvm( 587): Exception java/lang/UnsatisfiedLinkError from Class.java:414 not caught locally
W/dalvikvm( 587): threadid=15: thread exiting with uncaught exception (group=0×4000e648)
E/AndroidRuntime( 587): Uncaught handler: thread TestHsmClient0 exiting due to uncaught exception
E/AndroidRuntime( 587): java.lang.UnsatisfiedLinkError: getDeclaredClasses
E/AndroidRuntime( 587): at java.lang.Class.getDeclaredClasses(Native Method)
E/AndroidRuntime( 587): at java.lang.Class.getFullListOfClasses(Class.java:414)
E/AndroidRuntime( 587): at java.lang.Class.getClasses(Class.java:172)
E/AndroidRuntime( 587): at com.saville.android.testhsm1.TestHsmClient$MyHsm.build(TestHsmClient.java:40)
E/AndroidRuntime( 587): at com.saville.android.testhsm1.TestHsmClient$MyHsm.<init>(TestHsmClient.java:34)
E/AndroidRuntime( 587): at com.saville.android.testhsm1.TestHsmClient.InitHsm(TestHsmClient.java:21)
E/AndroidRuntime( 587): at com.saville.android.hsm1.ActiveHsm.run(ActiveHsm.java:59)
E/AndroidRuntime( 587): at java.lang.Thread.run(Thread.java:896)
I/Process ( 461): Sending signal. PID: 587 SIG: 3
I/dalvikvm( 587): threadid=7: reacting to signal 3
Bummer.
I then searched for <java find all private classes> and came across this. “Locating all classes implementing a given interface?”. Exactly what I wanted, there were two replies to the post. One says use “ServiceLoader” the other says; “Manually scan the classes in the jar file” or “in your manifest.mf file”. Its interesting that Android has taken the approach of a manifest file. I did a quick search for ServiceLoader its manifest based also.
Android provides a IPC (Inter-Process Communication) mechanism that is the preferred mechanism for communicating between process. The surprising thing to me is that this interface is synchronous.
What is so surprising is that communication across processes is inherently slow and not reliable and they recognize that when Activities communicate they suggest using messaging (Intents) . But when you create a Service and want to “bind” to that service so you can communicate bi-directionally, i.e. the Service is returning information to its client. You use aidl/IBinder which is a JMI type interface where the services are exposed as a series of method calls which are synchronous.
Of course since bound interfaces are synchronous they advise against using it to communicate directly between the Service and an Activity as can be seen here:
“IPC calls are synchronous. If you know that an IPC service takes more than a few milliseconds to complete, you should not call it in the Activity/View thread, because it might hang the application (Android might display an “Application is Not Responding” dialog).”
So it seems if there is a remote Service you wish to bind to you need to create a Local Service with an asynchronous interface to your Activity and a synchronous interface to the Remote Service.
Weird!
I was looking at ServiceStartArguments.java beneath the android samples directory and wondering how a Service gets its messages. So I thought I’d dissect ServiceStartArguments.java to learn.
The code extends Service and implements Runnable. Because it extends Service its onCreate() is invoked once for the life time of the service when the first Context.startService() is called. Then Context.startService invokes onStart() as defined by a Services Lifecycle. In ServiceStartArguments.onCreate() instantiates a new Intent() which is used when sending notifications in the handler. It also creates and starts a Java Thread.
Next onStart() and run() will be called, but you have no idea the order so we see that in onStart() looping waiting for mServiceHandler to be created by run(). After which it can gets a message (obtainMessage()) which has its target field set to itself and thus sends the startId and arguments to itself.
In run() frist calls Looper.prepare() this is a factory method which creates the one and only Looper for this thread. The Looper() constructor creates the threads MessageQueue and then Looper.myLooper() returns the Looper instance created by prepare().
When I first looked at this code I couldn’t figure how myLooper() worked as there was no parameter. Typically, a factory method like this would return an ID which I would have expected to be passed as a parameter to myLooper() but that wasn’t the case. Instead the Looper() instance is stored as a ThreadLocal<> variable and hence is always available. This also means Looper doesn’t needs dynamic arrays to manage an unknown number of Looper’s, nice.
Next, run() creates the ServiceHandler which extends Handler and then calls Looper.loop() which loops getting a message via MessageQueue.next() and dispatching via dispatchingMessage(). Looper.loop() terminates if a message is null, Message.target is null or there is an exception.
An important item is that Handler.obtainMessage() needs to know the its own messageQueue, which is in the Looper. This is accomplished by Looper being created before Handler and then Handler can use the Looper.myLooper() to retrieve the threads Looper from the ThreadLocal<> storage.
So in review, an Android service is has-a MessageQueue created by a Looper and one or more Handlers which are the targets of messages. A Handler has an associated Looper either directly associated in the handler constructor or implicitly associated by the Looper associated with the service’s thread.
I posted this message to the git email list asking about the Eclipse workspace/.metadata directory. Shawn Pearse repsonded and indicated that .metadata should be added to .git/info/exclude. I did so then removed it from my repo and and restarted Eclipse. Not expectedly, with .metadata gone Eclipse kind of forget things, such as the Projects and in my setup the location of the Android SDK.
It boots up into is fresh start screen, the first thing to do before “importing” the projects is to set the Android SDK Location in the menu “Windows/Preferences/Android/SDK Location”.
After doing that use menu “File/import/Existing Projects into Workspace”. Browse to “Select root directory” and add the appropriate projects. That seems to be enough.
The log class seems quite nice, so I started a work-a-like, turns out that taking advantage of variable number of parameter syntax makes it easier and faster. I suspect it will grow significantly over time:
package com.saville.debug.android;
public final class Log {
/**
* Log verbosely.
*
* On the android emulator this:
* Log.v(TAG, "onCreate: dispatchInvoke dur=%fs rate=%f/s", dur, (count / dur));
* was 5 times faster than this:
* Log.v(TAG, "onCreate: dispatchDirect dur=" + dur + "s rate=" + (count / dur) + "/s");
* The former took 0.005secs and the later about 0.02secs
*
* @param tag Identification
* @param fmt Format string as in printf
* @param args Variable number of arguments
*/
public static void v(String tag, String fmt, Object... args) {
android.util.Log.v(tag, String.format(fmt, args));
}
}
I wanted to time how fast different approaches might be in for dispatching to states in a state machine. At first I used android.os.SystemClock.uptimeMillis() but I thought there should be something more portable. I did a web search and found that in Java 5.0 System.nanoTime() was added and in fact found that it is implemented in Android so I abstracted away the time base:
static final long readTsc() {
return System.nanoTime();
}
static final double tscToSecs(long tsc) {
return tsc / 1000000000.0;
}
I also tested the speed of 10 in a row and when executing on the android emulator I get the following:
V/TestSm ( 586): s[0]=1376737118000 diff=0.000000ns
V/TestSm ( 586): s[1]=1376737159000 diff=41000.000000ns
V/TestSm ( 586): s[2]=1376737178000 diff=19000.000000ns
V/TestSm ( 586): s[3]=1376737196000 diff=18000.000000ns
V/TestSm ( 586): s[4]=1376737214000 diff=18000.000000ns
V/TestSm ( 586): s[5]=1376737231000 diff=17000.000000ns V/TestSm ( 586): s[6]=1376737249000 diff=18000.000000ns
V/TestSm ( 586): s[7]=1376737267000 diff=18000.000000ns
V/TestSm ( 586): s[8]=1376737285000 diff=18000.000000ns
V/TestSm ( 586): s[9]=1376737302000 diff=17000.000000ns
When I execute this on my Intel developement system, a 6600 @ 2.4GHz the following is seen:
Tests: s[0]=15759382032271 diff=0ns
Tests: s[1]=15759382033117 diff=846ns
Tests: s[2]=15759382033529 diff=412ns
Tests: s[3]=15759382033918 diff=389ns
Tests: s[4]=15759382034300 diff=382ns
Tests: s[5]=15759382034693 diff=393ns
Tests: s[6]=15759382035083 diff=390ns
Tests: s[7]=15759382035442 diff=359ns
Tests: s[8]=15759382035801 diff=359ns
Tests: s[9]=15759382036161 diff=360ns
Greater than 40 times faster on my Intel box than the android editor. That would be expected, but even 41us isn’t too bad compared to the 439us for the android.os.SystemClock.uptimeMillis().
I’ve also created a class so I can easily use this as I develop the state machine code:
package com.saville.debug.android;
public final class Timing {
public static final long readTsc() {
return System.nanoTime();
}
public static final double tscToSecs(long tsc) {
return (tsc / 1000000000.0);
}
public static final double tscToMillis(long tsc) {
return (tsc / 1000000.0);
}
public static final double tscToUsecs(long tsc) {
return (tsc / 1000.0);
}
public static final double tscToNanos(long tsc) {
return ((double)tsc);
}
}
Here was the link which helped me move an Eclipse project to a different directory. I had had the android projects in ~/prgs/android and wanted to move them to ~/workspace/android. Turns out you use Eclipse menu “File/import/Existing Projects into Workspace” to do that.