Android 2.2's most important improvement is without doubt the significantly faster virtual machine. The API, however, got some new features too. For me, the most intriguing new feature is the access to Google's experimental push services.
I have already posted about push feature in relation to iBus//Mobile asynchronous communication package so push is not new to Android. There are also open source alternatives like MQTT, Deacon or Urban Airship. It has also been present in certain Google applications from the beginning. Whenever Android Gmail application sends a notification when a new mail arrives on the server, you see push in operation. It is pretty fast, according to my experiences, even though time to time it takes longer time for the notification to arrive. 2.2 opened that already existing mechanism to general-purpose applications, even though the push service is still in early beta.
In order to do push, either one has proper push bearer (a network mechanism able to deliver unsolicited messages to the device) or such mechanism is simulated. Currently only two real push bearers are deployed widely on mobile networks, SMS and Blackberry's proprietary push solution. SMS is costly and the Blackberry solution is available only for Blackberry so the push bearer has to be simulated. The most common simulation method relies on the device to open a TCP connection to the push server. As the TCP stream is full-duplex, the server can send the push message to the device, provided that the stream is still alive. And that's the tricky bit whose complexity should not be underestimated. TCP streams time out if there is no communication on them and the other side does not necessarily notice it. A constant ping-pong traffic needs to be generated to prevent this. Frequency, however, is critical. Too frequent ping-pongs and the data cost associated to ping-ponging will be unacceptable and the battery is drawn down quickly. Too rare ping-pongs and the device or the server will not notice that the TCP stream was closed, only after a long timeout. For the user, it means that he did not get his urgent message immediately, only after, say, an hour.
There is no perfect solution to this problem, therefore it is a good feeling that Google made its best to create a simulated push bearer, along with the server that is able to keep that many TCP sockets open and shared that infrastructure with us. The Google push architecture has the following elements.
- The device that authenticates and registers with the push server (Cloud to Device Messaging in Google lingo) and provides authentication ticket to the 3rd Party Application Server.
- 3rd Party Application Server that uses the authentication ticket generated by the device to send push requests to the push server.
- Push server provided by Google that authenticates push requests from 3rd Party Application Servers and delivers the messages to the devices.
Cloud to Device Messaging (C2DM) has many tricky aspects but I wanted to create a test program that is as simple as possible. To try it out, you need the following:
- A PC connected to the Internet so that Google C2DM servers can be reached (and C2DM servers can reach us).
- Android emulator with 2.2+Google API AVD created (API level 8).
- Google App Engine SDK for Python.
- A Google account that you register with Google for push. It is better not to use your real e-mail address because you have to insert the password for this account into the server script. Use aexp.push as package name for the application in the registration form.
- Unpack the download package. Start the Android emulator. Create a Google account if no such account exists (Settings/Accounts & sync). This account does not have to be the same that you registered for push, it can be any Google account that you know the password for.
- Enter the "client" directory in the download package, update client/src/aexp/push/Config.java with the Google account you registered for push (C2DM_SENDER)
- Open server/pushserver/pushserver.py and update it with your push Google account (lines 165 and 167). Unfortunately here you have to insert the password for your push Google account into the server script.
- Enter the "server" directory, customize "ae_pushserver.sh" according to your directory layout and start it. Google App Engine SDK starts.
- Start the Push application on the emulator, select the account using the Menu and wait for the "Registered" message to appear. Now the server application is ready to deliver push messages.
- Go to http://localhost:8080 with your browser and type a message. Select the account from the drop-down list that you configured on the device and click the submit button. The message should appear on the emulator screen.
If you want to do the same trick from a real phone, you need a server with fix IP address or a fix DNS name and run the App Engine SDK there. Or better, deploy it on the real thing, on Google infrastructure. In any case, make sure that you update the server address in client/src/aexp/push/Config.java (and delete client/bin/classes directory as there are occassionally troubles with javac's dependency resolution).
About the application. The application reuses c2dm utility library from the JumpNote sample application. When the account is selected, the application registers with the push server using the phone user's credentials and the application ID that you registered with Google. Then comes the interesting bit. After the application registers with the push server, it sends the registration ID to the application server. The application server will use the registration ID to talk to the push server when it wants to do push. The server uses the Google account that you selected for push for authentication and therefore it needs the password for this account.
The implementation in the example application server program is a not efficient as it always requests an authentication token before it sends the push message. In an efficient implementation the token can be requested only once and can be used to authenticate many messages. Eventually the token expires and only then should new authentication token requested.
The client application also sends the client account name to the server but it is not used for authentication, it is only needed so that you can select the push target by account name in the web application's drop-down menu.