Just some thoughts I had.
1 seems problematic because you end up dealing with the situation you're trying to resolve because at some point the updater will need updating.
3 sounds good but if by "swapped out" you mean using some fancy reflection to load the dll during run time I'm not sure if performance will become an issue.
There is a fourth option where the service can spawn an update process which would allow it to update the update executable if necessary before running it. From there it's a simple matter of writing an installation app which the service will spawn just before shutting down.