To add to what has been said already.
In my company, we used to deal with OTA firmware updates a lot. We used a bootloader and 2 flash partitions for an app.
In our case, customers also stored some configuration data on flash, which was part of an app partition.
So, sometimes a new image was perfectly fine, all checksums are OK. But their custom configuration, for one or another reason, bricked a device. The same binary worked fine on 1000 devices, but bricked the 1001st.
The solution for that was a to use a "blessed" marker, somewhere in the flash. A current firmware image is "blessed", a new one is not. The bootloader flashes a new app partition, verifies checksums, and reboots - into that NEW partition, which is not yet marked as blessed. At the same time, it starts a hardware timer that simply reboots the device in X amount of seconds. That X seconds should be enough to boot, initialize, verify the new functionality, and "bless" a new partition manually by some user action - so on the next reboot, a new firmware gets booted.
If a device hangs, crashes, or whatever - a HW timer restarts a device, and it reboots back to the old "blessed" partition.
This way, we used to OTA even very dodgy, bad firmwares in field, and that mechanism was always rebooting the good firmware back on any trouble - for example, if we lost connection with a device.