libavb: Move all A/B functionality into separate libavb_ab/ directory.

This new libavb_ab "library" depends on libavb "library" insofar that
it's using the same abstractions (system dependencies and
operations). For easy integration the newly introduced AvbABOps struct
extends the AvbOps struct so users can build just a single struct and
use that for both.

Also emphasize in README that libavb_ab usage is optional and that
it's possible to integrate libavb with another A/B stack.

(The quotes in use for "library" above is because these are not really
libraries from a system-integration perspective. That is, 3rd party is
expected to integrate this source-code with their own build-system and
toolchain.)

Since we now have multiple libraries - at least from the point of view
of how it's used in unit tests - change Android.mk such that library
users need to use libavb/libavb.h and libavb_ab/libavb_ab.h instead of
just e.g. libavb.h.

Test: Unit tests pass
Test: Tested in UEFI-based bootloader in qemu.
Test: Tested boot_control.avb.so in same UEFI-based system.
Bug: None

Change-Id: I19ea8f6bd1e63b2617b0e9fa9fc3b2a68ac4a92e
diff --git a/libavb_ab/avb_ab_flow.c b/libavb_ab/avb_ab_flow.c
new file mode 100644
index 0000000..da8e4ea
--- /dev/null
+++ b/libavb_ab/avb_ab_flow.c
@@ -0,0 +1,431 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use, copy,
+ * modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "avb_ab_flow.h"
+
+bool avb_ab_data_verify_and_byteswap(const AvbABData* src, AvbABData* dest) {
+  /* Ensure magic is correct. */
+  if (avb_safe_memcmp(src->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN) != 0) {
+    avb_error("Magic is incorrect.\n");
+    return false;
+  }
+
+  avb_memcpy(dest, src, sizeof(AvbABData));
+  dest->crc32 = avb_be32toh(dest->crc32);
+
+  /* Ensure we don't attempt to access any fields if the major version
+   * is not supported.
+   */
+  if (dest->version_major > AVB_AB_MAJOR_VERSION) {
+    avb_error("No support for given major version.\n");
+    return false;
+  }
+
+  /* Bail if CRC32 doesn't match. */
+  if (dest->crc32 !=
+      avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t))) {
+    avb_error("CRC32 does not match.\n");
+    return false;
+  }
+
+  return true;
+}
+
+void avb_ab_data_update_crc_and_byteswap(const AvbABData* src,
+                                         AvbABData* dest) {
+  avb_memcpy(dest, src, sizeof(AvbABData));
+  dest->crc32 = avb_htobe32(
+      avb_crc32((const uint8_t*)dest, sizeof(AvbABData) - sizeof(uint32_t)));
+}
+
+void avb_ab_data_init(AvbABData* data) {
+  avb_memset(data, '\0', sizeof(AvbABData));
+  avb_memcpy(data->magic, AVB_AB_MAGIC, AVB_AB_MAGIC_LEN);
+  data->version_major = AVB_AB_MAJOR_VERSION;
+  data->version_minor = AVB_AB_MINOR_VERSION;
+  data->slots[0].priority = AVB_AB_MAX_PRIORITY;
+  data->slots[0].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+  data->slots[0].successful_boot = 0;
+  data->slots[1].priority = AVB_AB_MAX_PRIORITY - 1;
+  data->slots[1].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+  data->slots[1].successful_boot = 0;
+}
+
+/* The AvbABData struct is stored 2048 bytes into the 'misc' partition
+ * following the 'struct bootloader_message' field. The struct is
+ * compatible with the guidelines in bootable/recovery/bootloader.h -
+ * e.g. it is stored in the |slot_suffix| field, starts with a
+ * NUL-byte, and is 32 bytes long.
+ */
+#define AB_METADATA_MISC_PARTITION_OFFSET 2048
+
+AvbIOResult avb_ab_data_read(AvbABOps* ab_ops, AvbABData* data) {
+  AvbOps* ops = &(ab_ops->ops);
+  AvbABData serialized;
+  AvbIOResult io_ret;
+  size_t num_bytes_read;
+
+  io_ret =
+      ops->read_from_partition(ops, "misc", AB_METADATA_MISC_PARTITION_OFFSET,
+                               sizeof(AvbABData), &serialized, &num_bytes_read);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    return AVB_IO_RESULT_ERROR_OOM;
+  } else if (io_ret != AVB_IO_RESULT_OK ||
+             num_bytes_read != sizeof(AvbABData)) {
+    avb_error("Error reading A/B metadata.\n");
+    return AVB_IO_RESULT_ERROR_IO;
+  }
+
+  if (!avb_ab_data_verify_and_byteswap(&serialized, data)) {
+    avb_error(
+        "Error validating A/B metadata from disk. "
+        "Resetting and writing new A/B metadata to disk.\n");
+    avb_ab_data_init(data);
+    return avb_ab_data_write(ab_ops, data);
+  }
+
+  return AVB_IO_RESULT_OK;
+}
+
+AvbIOResult avb_ab_data_write(AvbABOps* ab_ops, const AvbABData* data) {
+  AvbOps* ops = &(ab_ops->ops);
+  AvbABData serialized;
+  AvbIOResult io_ret;
+
+  avb_ab_data_update_crc_and_byteswap(data, &serialized);
+  io_ret =
+      ops->write_to_partition(ops, "misc", AB_METADATA_MISC_PARTITION_OFFSET,
+                              sizeof(AvbABData), &serialized);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    return AVB_IO_RESULT_ERROR_OOM;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("Error writing A/B metadata.\n");
+    return AVB_IO_RESULT_ERROR_IO;
+  }
+  return AVB_IO_RESULT_OK;
+}
+
+static bool slot_is_bootable(AvbABSlotData* slot) {
+  return slot->priority > 0 &&
+         (slot->successful_boot || (slot->tries_remaining > 0));
+}
+
+static void slot_set_unbootable(AvbABSlotData* slot) {
+  slot->priority = 0;
+  slot->tries_remaining = 0;
+  slot->successful_boot = 0;
+}
+
+/* Ensure all unbootable and/or illegal states are marked as the
+ * canonical 'unbootable' state, e.g. priority=0, tries_remaining=0,
+ * and successful_boot=0.
+ */
+static void slot_normalize(AvbABSlotData* slot) {
+  if (slot->priority > 0) {
+    if (slot->tries_remaining == 0 && !slot->successful_boot) {
+      /* We've exhausted all tries -> unbootable. */
+      slot_set_unbootable(slot);
+    }
+    if (slot->tries_remaining > 0 && slot->successful_boot) {
+      /* Illegal state - avb_ab_mark_slot_successful() will clear
+       * tries_remaining when setting successful_boot.
+       */
+      slot_set_unbootable(slot);
+    }
+  } else {
+    slot_set_unbootable(slot);
+  }
+}
+
+static const char* slot_suffixes[2] = {"_a", "_b"};
+
+/* Helper function to load metadata - returns AVB_IO_RESULT_OK on
+ * success, error code otherwise.
+ */
+static AvbIOResult load_metadata(AvbABOps* ab_ops, AvbABData* ab_data,
+                                 AvbABData* ab_data_orig) {
+  AvbIOResult io_ret;
+
+  io_ret = ab_ops->read_ab_metadata(ab_ops, ab_data);
+  if (io_ret != AVB_IO_RESULT_OK) {
+    avb_error("I/O error while loading A/B metadata.\n");
+    return io_ret;
+  }
+  *ab_data_orig = *ab_data;
+
+  /* Ensure data is normalized, e.g. illegal states will be marked as
+   * unbootable and all unbootable states are represented with
+   * (priority=0, tries_remaining=0, successful_boot=0).
+   */
+  slot_normalize(&ab_data->slots[0]);
+  slot_normalize(&ab_data->slots[1]);
+  return AVB_IO_RESULT_OK;
+}
+
+/* Writes A/B metadata to disk only if it has changed - returns
+ * AVB_IO_RESULT_OK on success, error code otherwise.
+ */
+static AvbIOResult save_metadata_if_changed(AvbABOps* ab_ops,
+                                            AvbABData* ab_data,
+                                            AvbABData* ab_data_orig) {
+  if (avb_safe_memcmp(ab_data, ab_data_orig, sizeof(AvbABData)) != 0) {
+    avb_debug("Writing A/B metadata to disk.\n");
+    return ab_ops->write_ab_metadata(ab_ops, ab_data);
+  }
+  return AVB_IO_RESULT_OK;
+}
+
+AvbABFlowResult avb_ab_flow(AvbABOps* ab_ops,
+                            const char* const* requested_partitions,
+                            AvbSlotVerifyData** out_data) {
+  AvbOps* ops = &(ab_ops->ops);
+  AvbSlotVerifyData* slot_data[2] = {NULL, NULL};
+  AvbSlotVerifyData* data = NULL;
+  AvbABFlowResult ret;
+  AvbABData ab_data, ab_data_orig;
+  size_t slot_index_to_boot, n;
+  AvbIOResult io_ret;
+
+  io_ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+  if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+    ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+    goto out;
+  } else if (io_ret != AVB_IO_RESULT_OK) {
+    ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+    goto out;
+  }
+
+  /* Validate all bootable slots. */
+  for (n = 0; n < 2; n++) {
+    if (slot_is_bootable(&ab_data.slots[n])) {
+      AvbSlotVerifyResult verify_result;
+      verify_result = avb_slot_verify(ops, requested_partitions,
+                                      slot_suffixes[n], &slot_data[n]);
+      if (verify_result != AVB_SLOT_VERIFY_RESULT_OK) {
+        if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_OOM) {
+          ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+          goto out;
+        }
+        if (verify_result == AVB_SLOT_VERIFY_RESULT_ERROR_IO) {
+          ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+          goto out;
+        }
+        avb_errorv("Error verifying slot ", slot_suffixes[n], " with result ",
+                   avb_slot_verify_result_to_string(verify_result),
+                   " - setting unbootable.\n", NULL);
+        slot_set_unbootable(&ab_data.slots[n]);
+      }
+    }
+  }
+
+  if (slot_is_bootable(&ab_data.slots[0]) &&
+      slot_is_bootable(&ab_data.slots[1])) {
+    if (ab_data.slots[1].priority > ab_data.slots[0].priority) {
+      slot_index_to_boot = 1;
+    } else {
+      slot_index_to_boot = 0;
+    }
+  } else if (slot_is_bootable(&ab_data.slots[0])) {
+    slot_index_to_boot = 0;
+  } else if (slot_is_bootable(&ab_data.slots[1])) {
+    slot_index_to_boot = 1;
+  } else {
+    /* No bootable slots! */
+    avb_error("No bootable slots found.\n");
+    ret = AVB_AB_FLOW_RESULT_ERROR_NO_BOOTABLE_SLOTS;
+    goto out;
+  }
+
+  /* Update stored rollback index such that the stored rollback index
+   * is the largest value supporting all currently bootable slots. Do
+   * this for every rollback index slot.
+   */
+  for (n = 0; n < AVB_MAX_NUMBER_OF_ROLLBACK_INDEX_SLOTS; n++) {
+    uint64_t rollback_index_value = 0;
+
+    if (slot_data[0] != NULL && slot_data[1] != NULL) {
+      uint64_t a_rollback_index = slot_data[0]->rollback_indexes[n];
+      uint64_t b_rollback_index = slot_data[1]->rollback_indexes[n];
+      rollback_index_value =
+          (a_rollback_index < b_rollback_index ? a_rollback_index
+                                               : b_rollback_index);
+    } else if (slot_data[0] != NULL) {
+      rollback_index_value = slot_data[0]->rollback_indexes[n];
+    } else if (slot_data[1] != NULL) {
+      rollback_index_value = slot_data[1]->rollback_indexes[n];
+    }
+
+    if (rollback_index_value != 0) {
+      uint64_t current_rollback_index_value;
+      io_ret = ops->read_rollback_index(ops, n, &current_rollback_index_value);
+      if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+        ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+        goto out;
+      } else if (io_ret != AVB_IO_RESULT_OK) {
+        avb_error("Error getting rollback index for slot.\n");
+        ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+        goto out;
+      }
+      if (current_rollback_index_value != rollback_index_value) {
+        io_ret = ops->write_rollback_index(ops, n, rollback_index_value);
+        if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+          ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+          goto out;
+        } else if (io_ret != AVB_IO_RESULT_OK) {
+          avb_error("Error setting stored rollback index.\n");
+          ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+          goto out;
+        }
+      }
+    }
+  }
+
+  /* Finally, select this slot. */
+  avb_assert(slot_data[slot_index_to_boot] != NULL);
+  data = slot_data[slot_index_to_boot];
+  slot_data[slot_index_to_boot] = NULL;
+  ret = AVB_AB_FLOW_RESULT_OK;
+
+  /* ... and decrement tries remaining, if applicable. */
+  if (!ab_data.slots[slot_index_to_boot].successful_boot &&
+      ab_data.slots[slot_index_to_boot].tries_remaining > 0) {
+    ab_data.slots[slot_index_to_boot].tries_remaining -= 1;
+  }
+
+out:
+  io_ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+  if (io_ret != AVB_IO_RESULT_OK) {
+    if (io_ret == AVB_IO_RESULT_ERROR_OOM) {
+      ret = AVB_AB_FLOW_RESULT_ERROR_OOM;
+    } else {
+      ret = AVB_AB_FLOW_RESULT_ERROR_IO;
+    }
+    if (data != NULL) {
+      avb_slot_verify_data_free(data);
+      data = NULL;
+    }
+  }
+
+  for (n = 0; n < 2; n++) {
+    if (slot_data[n] != NULL) {
+      avb_slot_verify_data_free(slot_data[n]);
+    }
+  }
+
+  if (out_data != NULL) {
+    *out_data = data;
+  } else {
+    if (data != NULL) {
+      avb_slot_verify_data_free(data);
+    }
+  }
+
+  return ret;
+}
+
+AvbIOResult avb_ab_mark_slot_active(AvbABOps* ab_ops,
+                                    unsigned int slot_number) {
+  AvbABData ab_data, ab_data_orig;
+  unsigned int other_slot_number;
+  AvbIOResult ret;
+
+  avb_assert(slot_number < 2);
+
+  ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+  if (ret != AVB_IO_RESULT_OK) {
+    goto out;
+  }
+
+  /* Make requested slot top priority, unsuccessful, and with max tries. */
+  ab_data.slots[slot_number].priority = AVB_AB_MAX_PRIORITY;
+  ab_data.slots[slot_number].tries_remaining = AVB_AB_MAX_TRIES_REMAINING;
+  ab_data.slots[slot_number].successful_boot = 0;
+
+  /* Ensure other slot doesn't have as high a priority. */
+  other_slot_number = 1 - slot_number;
+  if (ab_data.slots[other_slot_number].priority == AVB_AB_MAX_PRIORITY) {
+    ab_data.slots[other_slot_number].priority = AVB_AB_MAX_PRIORITY - 1;
+  }
+
+  ret = AVB_IO_RESULT_OK;
+
+out:
+  if (ret == AVB_IO_RESULT_OK) {
+    ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+  }
+  return ret;
+}
+
+AvbIOResult avb_ab_mark_slot_unbootable(AvbABOps* ab_ops,
+                                        unsigned int slot_number) {
+  AvbABData ab_data, ab_data_orig;
+  AvbIOResult ret;
+
+  avb_assert(slot_number < 2);
+
+  ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+  if (ret != AVB_IO_RESULT_OK) {
+    goto out;
+  }
+
+  slot_set_unbootable(&ab_data.slots[slot_number]);
+
+  ret = AVB_IO_RESULT_OK;
+
+out:
+  if (ret == AVB_IO_RESULT_OK) {
+    ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+  }
+  return ret;
+}
+
+AvbIOResult avb_ab_mark_slot_successful(AvbABOps* ab_ops,
+                                        unsigned int slot_number) {
+  AvbABData ab_data, ab_data_orig;
+  AvbIOResult ret;
+
+  avb_assert(slot_number < 2);
+
+  ret = load_metadata(ab_ops, &ab_data, &ab_data_orig);
+  if (ret != AVB_IO_RESULT_OK) {
+    goto out;
+  }
+
+  if (!slot_is_bootable(&ab_data.slots[slot_number])) {
+    avb_error("Cannot mark unbootable slot as successful.\n");
+    ret = AVB_IO_RESULT_OK;
+    goto out;
+  }
+
+  ab_data.slots[slot_number].tries_remaining = 0;
+  ab_data.slots[slot_number].successful_boot = 1;
+
+  ret = AVB_IO_RESULT_OK;
+
+out:
+  if (ret == AVB_IO_RESULT_OK) {
+    ret = save_metadata_if_changed(ab_ops, &ab_data, &ab_data_orig);
+  }
+  return ret;
+}