libsnapshot: Implement merge flow.

This implements InitiateMerge() and WaitForMerge(). InitiateMerge() is
meant to be called after an update has been marked successful.
WaitForMerge() is designed to be called either: immediately after
InitiateMerge, or during each subsequent boot where merging has not
completed.

InitiateMerge converts each snapshot device to a snapshot-merge device.

WaitForMerge polls each snapshot-merge device until no device reports a
"merging" state. One of the following states can result from this:
 - MergeFailed. This will happen if any device failed to merge, or we
   were unable to poll, or any other system-level failure occurred.
 - MergeNeedsReboot. This will happen if a snapshot-merge device has
   completed merging, but we were unable to clean it up due to something
   holding a resource open.
 - MergeCompleted. This indicates that all snapshots completed merging
   and were cleaned up.

If WaitForMerge() returns MergeCompleted, then all snapshots have been
removed and a new update can begin. GetUpdateState() will return None.

MergeFailed and MergeNeedsReboot, on the other hand, are "sticky". They
indicate a merge is still pending. When called again, WaitForMerge()
will poll again to attempt to make more progress in the merge. For
NeedsReboot, a single reboot will ensure all resources are released and
the next WaitForMerge() will successfully finish cleanup. In the failure
case, it is unlikely the next WaitForMerge will succeed, but we always
retry anyway (there is no harm in doing so, and if we get lucky, the
device can take more OTAs).

Bug: 136678799
Test: libsnapshot_test gtests
Change-Id: I5e93fcbffee1973da5ff76363df12d6317a7a7c7
4 files changed