Bitcoin Core does this thing called non-atomic flushing. What that means is that the database, instead of being updated atomically (i.e. everything is written at the same time, or nothing is written), has data written to it over time. If the database crashes, with non-atomic flushing, there will be some data written, and some data that is not written. This is different from atomic flushing where either all of the data was written, or none of it was.
Non-atomic flushing allows Bitcoin Core to skip validation of things it has already validated and then just flush things to the database later after a crash or unclean shutdown. But in order to know where it has validated up to, it has to store that block hash (where it has validated up to and where it is flushing up to). It also has to store the block it started at (the block the database knew up to when flushing began).
This is where
GetHeadBlocks() comes in. When Bitcoin Core begins flushing, it first writes those two blocks, the old one where the database head was at, and the new one, where the database head will be once flushing finishes. In the event of an unclean shutdown or database crash, these values are already written to the database so it can pull those out of the database, know where its last known good database state was at, and know where it has validated up to so it can skip full validation and just build the database data and flush it. If there was no unclean shutdown or crash,
GetHeadBlocks() would return an empty vector.
For example, suppose the database was at block 50, and it is flushing to block 60. When it begins flushing, the hashes of blocks 50 and 60 are written to the database. Suppose that the computer suddenly loses power when it has only flushed up to block 55. When the node comes back on, it will call
GetHeadBlocks() and get the hashes of blocks 50 and 60. Now it knows that it was mid-flush when it uncleanly shutdown. So it then rebuilds what the database would be from blocks 50 to 60 but does not perform full validation. It then flushes the remaining data and removes the hashes of blocks 50 and 60 from where they were written.