Search code examples
androidandroid-contactssamsung-mobileandroid-syncadapter

How to handle "SQLiteException: null" from ContentResolver.applyBatch?


I have implemented a SyncAdapter which writes data to the Android Contacts Provider. Mostly, this appears to be working fine, except for a small percentage of my users, who see the app crash every time the SyncAdapter fires! When I recover the logs from these devices (primarily Samsung devices running Android 5+), this is what I see:

exception: android.database.sqlite.SQLiteException: null
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:181)
at android.database.DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel(DatabaseUtils.java:160)
at android.content.ContentProviderProxy.applyBatch(ContentProviderNative.java:520)
at android.content.ContentProviderClient.applyBatch(ContentProviderClient.java:402)
at android.content.ContentResolver.applyBatch(ContentResolver.java:1297)

Now, it appears that ContentProviderProxy.applyBatch works by bundling up its data into a message which is sent via IBinder to whatever service is in charge of managing the contacts database. In turn, it receives a message back, and then passes that along to DatabaseUtils.readExceptionWithOperationApplicationExceptionFromParcel. This function inspects the reply, and based upon the passed code, is supposed to throw an Exception with the String message in the reply. Unfortunately, in this case, although the service has set a code in the reply, there is no message set; and that's why I see SQLiteException: null and I am left with no clue about what I'm doing wrong.

Is anyone else experiencing this error, and if so, can you help me narrow down what is happening in this case? Thanks!


Solution

  • I ran into it. It's caused by a Contacts database corruption. The full details are on my post to the Samsung Developers forum.

    The only workaround I found is to catch SQLiteException in your syncing method, then inform the user that he has to clear the Contacts database (he might lose local contacts!). The intent is:

    Intent detailsIntent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
    detailsIntent.setData(Uri.parse("package:com.android.providers.contacts"));
    

    Once the data is cleared, the contacts will resync and the database will get rebuilt properly.