This answer is a bit late, but I guess it might still help someone.
The implementation of CalendarContract has many flaws which never seem to be fixed in new Android versions and which are not documented.
In my experience, there's not much difference between limited and infinite recurrences, but the instances table might have more problem with infinite ones.
For all day events, the EXDATE should be just yyyymmdd, otherwise UTC time in yymmddThhmmssZ format. Comma-separated if more than one.
If it doesn't work, there might be something else that needs to be done differently, especially if EXDATE is set on an already existing event.
Recurring events must have DURATION set, non-recurring shoud set DTEND instead.
When updating an event, the update must include DTSTART, RRULE, DURATION (not sure if duration is really necessary), where DTSTART must be the same but RRULE MUST BE DIFFERENT!
If you update an event to add an EXDATE without changing RRULE, then RRULE is removed from the event so it becomes non-recurring (not immediately afterwards, wait a whole minute before checking). This seems to happen to calendars from a Google account, but not all types of account.
Just appending a ';' to RRULE in the update seems to work.
(Exceptions can also be created by adding a separate event referring to the recurring one instead of adding an EXDATE. I've never tried that)
The instances table has many flaws:
It may refuse to expand some recurring events or it may take hours to update.
It only seems to expand recurrences one year ahead.
It doesn't include the last instance of an all day event with end date (this might be different in eastern/western hemisphere)