Synchronization in Android

Tutorials with advanced 'difficulty' and more Lines of Code.

Synchronization in Android

Postby paller » Thu Feb 14, 2008 10:54 pm

Synchronization in Android


Click here for the cross-linked version of this entry.

Note: this example program was written before the new m5-rc14 release of the SDK was published and therefore it refers to m3-rc37a SDK release. I intend to investigate the sync issue in the new release too.

The first thing I noted about Android content providers that they support synchronization. This fact has huge implications and shows, how well the Android mobile platform is designed. Synchronization is a key enabler in mobile applications but is often "engineered in" later into the platforms. This approach is about as realistic as "adding security later" to a non security-aware platform.

It is not surprising for an Android-hardened developer that synchronization does not work in the m3-rc37a release and the example program presented here is not able to accomplish any real synchronization. This statement would discourage lesser programmers but not the ones dealing with the Android platform! Decyphering the Android synchronization framework is an interesting exercise in itself even though that framework may change in the future. Key elements are already there and there are some interesting findings regarding synchronization as a service.

You can download the example program from here.

The naive observation that led me to deal with the Android synchronization framework is that the log clearly indicates a running synchronization service. The synchronization service (actually called android.content.ContentService) listens to data connection/disconnection events and logs these state changes. In order to actually activate the sync part of the service (other part of the service deals with the XMPP connection), the following steps should be taken.

* The sync part of the service must be enabled by manipulating the sync_enabled property in the settings table. This is done by calling android.provider.Settings.Gservices.putString( cr,"sync_enabled","true" ). You noticed it well: the G in Gservices refers to Google. Clearly, Android sync framework programmers considered synchronization a Google service. In order for this call to succeed, the application must have android.permission.WRITE_SETTINGS permission (check the manifest of the example program).
* Account information must be provided. Interestingly again, the service handling this logic is called GoogleLoginService. ContentService obtains account information from GoogleLoginService and if there are no accounts specified, synchronization stops. This is a bit frightening but in m3-rc37a release the account information is stored in a local SQLite table. Do the following:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.       adb shell
  2.       cd data/data/com.google.android.providers.googleapps/databases
  3.       sqlite3 accounts.db
  4.       INSERT INTO "accounts" VALUES(1,'user','password',1);
  5.       .quit
  6.  
Parsed in 0.032 seconds, using GeSHi 1.0.8.4

* The sync engine stores its settings, history and stats in a content provider under the content://sync/ tree. Strangely, this content provider is not implemented at all. The example program provides a naive implementation which is good enough to make the sync service work.

The sync service is ready for work now. In Android, only synchronizable data providers can be synchronized and this makes this whole exercise more valuable than just pure hacking. Content providers must jump some fences to become synchronizable. Pretty few built-in content providers of the SDK are synchronizable (you can examine these lists using the example program's "List sync providers" and "List content provider" menu items).

The steps necessary to make a content provider synchronizable are the following:

* The content provider must be marked as synchronizable in the manifest (again, the XML fragment is mangled because of the limitations of the blog engine):
Syntax: [ Download ] [ Hide ]
Using xml Syntax Highlighting
  1. <provider class=".SimpleStringDataProvider"
  2.                    android:authorities="aexp.syncexample.SimpleString"
  3.                    android:syncable="true"/>
Parsed in 0.001 seconds, using GeSHi 1.0.8.4

* The content provider must be able to provide a temporary version of itself. The method signature is the following:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public ContentProvider getTemporaryInstance()
Parsed in 0.030 seconds, using GeSHi 1.0.8.4


The synchronization engine manipulates the temporary instance of the content provider and changes done on the temporary content provider are merged by another method the content provider must implement:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public MergeResult merge(SyncContext context, ContentProvider diffs, boolean readOnly)
Parsed in 0.034 seconds, using GeSHi 1.0.8.4


This latter method gets the temporary content provider instance after one synchronization step is finished on it and merges it with the main content provider. Meanwhile, collisions may be detected (data changed incompatibly on both sides since the last synchronization) and as a result, synchronization may even be interrupted by the user.
* And last, but not least, the synchronizable content provider must be able to return the SyncAdapter that is able to synchronize the provider.

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. public SyncAdapter getSyncAdapter(Context context)
Parsed in 0.035 seconds, using GeSHi 1.0.8.4


The SyncAdapter instance abstracts the entire synchronization engine. The example program provides a dummy implementation.

This is not enough. The database structure of the content provider must be designed in such a way that the SyncAdapter supported by the content provider is able to manipulate it. There are different synchronization strategies and android.provider.SyncColumns provides a number of columns that may be useful implementing them. The content provider in the example program supports the most common one, the timestamp-based synchronization. In this method, the "version" of a data item is expressed by a high-resolution timestamp. Each item timestamped after the timestamp of the last synchronization is candidate for sync processing.

The interaction between the sync engine and the sync adapter can be followed on the the log below:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. D/SyncExample(  614): syncDB
  2. D/SyncExample(  614): After syncDB
  3. D/Sync    (  467): running sync operation type: 1 url: content://aexp.syncexample.SimpleString
  4. D/ActivityThread(  467): Installing external provider aexp.syncexample.SimpleString: aexp.syncexample.SimpleStringDataProvider
  5. D/ActivityThread(  467): Installing external provider sync: aexp.syncexample.SyncSettingsProvider
  6. I/Sync    (  467): Starting sync for aexp.syncexample.SimpleString
  7. D/SyncAdapterStub(  614): syncStarting
  8. D/SyncAdapterStub(  614): isReadOnly
  9. D/SyncAdapterStub(  614): getServerDiffs, contentProvider: aexp.syncexample.SimpleStringDataProvider@40014470
  10. D/SIMPLESTRINGDATAPROVIDER(  614): merge, diffs: aexp.syncexample.SimpleStringDataProvider@40014470
  11. D/SIMPLESTRINGDATAPROVIDER(  614): merge, tempContentProvider: android.content.ContentProvider$Transport@400144a0
  12. D/SyncAdapterStub(  614): writeSyncData: aexp.syncexample.SimpleString
  13. D/SIMPLESTRINGDATAPROVIDER(  614): merge, diffs: null
  14. D/SyncAdapterStub(  614): syncEnding
  15. I/Sync    (  467): Ending sync for aexp.syncexample.SimpleString
  16. D/Sync    (  467): finished sync operation type: 1 url: content://aexp.syncexample.SimpleString
  17.  
Parsed in 0.040 seconds, using GeSHi 1.0.8.4


* In the first step, getServerDiffs is called on the SyncAdapter, using the temporary provider as input. In case of the timestamp-based adapter, the client-server communication must establish the timestamp at which this client and server synchronized last, send client changes after that timestamp and obtain changes from the server into the temporary provider.
* In the second step, the provider's merge method is called with the temporary provider as parameter. At this point the content provider must reconcile the client-side database with the temporary database. During the merging, collisions may be detected when the client and the server both changed a data item since the last synchronization in non-compatible way. Eventually collisions may need to be escalated to the user who may even interrupt the synchronization process.
* After this step, we have the reconciled database on the client side. The client now needs to notify the server about collision resolution and sends the client diffs one more time using the SyncAdapter's sendClientDiffs method. This step is not present in the log because our primitive synchronization example did not produce collisions.

After all this suffering, I guess, you would like to see a real synchronization session. I have to disappoint you: beside some scattered SyncML DS-related classes, I was not able to find any real sync adapter. Implementing a real synchronization engine takes a lot of time but I happen to have a SyncML-based engine implemented and I intend to put it under Android's sync framework. So stay tuned. :-)
paller
Developer
Developer
 
Posts: 29
Joined: Mon Dec 31, 2007 2:33 am
Location: London

Top

Postby buster » Wed Apr 23, 2008 1:37 pm

Great article.
Are there any news on your syncml-engine?
I want to use syncml in my android application and was looking for something i can use.
Will there be syncml-support in android? (or even better.. IS there something i can build on, without having to write a whole syncml-engine?)

Regards, Sebastian
buster
Junior Developer
Junior Developer
 
Posts: 23
Joined: Tue Apr 22, 2008 4:14 pm
Location: Berlin, Germany

Postby paller » Wed Apr 23, 2008 8:14 pm

buster wrote:Great article.
Are there any news on your syncml-engine?


I promised the adaptation but I spent my time on something else. :-/
The code is actually available here.
Scroll down to the middle of the page, look for the paper titled "Building reflective mobile middleware framework on top of the OSGi platform" and click on the "Sources of the framework" link.
The software needs significant adaptation, however, to work in Android environment,

buster wrote:I want to use syncml in my android application and was looking for something i can use.
Will there be syncml-support in android? (or even better.. IS there something i can build on, without having to write a whole syncml-engine?)
Regards, Sebastian


I cannot know. ;-) Logically, there should be a sync engine available if Android has a full framework for synchronization. I don't have further information, however.
paller
Developer
Developer
 
Posts: 29
Joined: Mon Dec 31, 2007 2:33 am
Location: London

About Sync Engine

Postby Zidane » Fri Apr 25, 2008 12:23 pm

You can use "Funambol",it offers a Sync Engine Server and APIs to communicate with others data sources.
Zidane
Once Poster
Once Poster
 
Posts: 1
Joined: Fri Apr 25, 2008 11:44 am

Re: Synchronization in Android

Postby white_gecko » Tue Aug 17, 2010 12:36 am

I think this thread is outdated, here is a very easy to understand workshop on creating a sync adapter: http://www.c99.org/2010/01/23/writing-an-android-sync-provider-part-1/
white_gecko
Freshman
Freshman
 
Posts: 7
Joined: Thu Jul 29, 2010 5:46 pm

Top

Return to Advanced Tutorials

Who is online

Users browsing this forum: No registered users and 3 guests