Home | History | Annotate | Download | only in boot_control
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Permission is hereby granted, free of charge, to any person
      5  * obtaining a copy of this software and associated documentation
      6  * files (the "Software"), to deal in the Software without
      7  * restriction, including without limitation the rights to use, copy,
      8  * modify, merge, publish, distribute, sublicense, and/or sell copies
      9  * of the Software, and to permit persons to whom the Software is
     10  * furnished to do so, subject to the following conditions:
     11  *
     12  * The above copyright notice and this permission notice shall be
     13  * included in all copies or substantial portions of the Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     18  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
     19  * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
     20  * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
     21  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     22  * SOFTWARE.
     23  */
     24 
     25 #include <errno.h>
     26 #include <string.h>
     27 
     28 #include <cutils/properties.h>
     29 #include <hardware/boot_control.h>
     30 #include <hardware/hardware.h>
     31 
     32 #include <libavb_ab/libavb_ab.h>
     33 #include <libavb_user/libavb_user.h>
     34 
     35 static AvbOps* ops = NULL;
     36 
     37 static void module_init(boot_control_module_t* module) {
     38   if (ops != NULL) {
     39     return;
     40   }
     41 
     42   ops = avb_ops_user_new();
     43   if (ops == NULL) {
     44     avb_error("Unable to allocate AvbOps instance.\n");
     45   }
     46 }
     47 
     48 static unsigned int module_getNumberSlots(boot_control_module_t* module) {
     49   return 2;
     50 }
     51 
     52 static unsigned int module_getCurrentSlot(boot_control_module_t* module) {
     53   char propbuf[PROPERTY_VALUE_MAX];
     54 
     55   property_get("ro.boot.slot_suffix", propbuf, "");
     56   if (strcmp(propbuf, "_a") == 0) {
     57     return 0;
     58   } else if (strcmp(propbuf, "_b") == 0) {
     59     return 1;
     60   } else {
     61     avb_errorv("Unexpected slot suffix '", propbuf, "'.\n", NULL);
     62     return 0;
     63   }
     64   return 0;
     65 }
     66 
     67 static int module_markBootSuccessful(boot_control_module_t* module) {
     68   if (avb_ab_mark_slot_successful(ops->ab_ops, module_getCurrentSlot(module)) ==
     69       AVB_IO_RESULT_OK) {
     70     return 0;
     71   } else {
     72     return -EIO;
     73   }
     74 }
     75 
     76 static int module_setActiveBootSlot(boot_control_module_t* module,
     77                                     unsigned int slot) {
     78   if (slot >= module_getNumberSlots(module)) {
     79     return -EINVAL;
     80   } else if (avb_ab_mark_slot_active(ops->ab_ops, slot) == AVB_IO_RESULT_OK) {
     81     return 0;
     82   } else {
     83     return -EIO;
     84   }
     85 }
     86 
     87 static int module_setSlotAsUnbootable(struct boot_control_module* module,
     88                                       unsigned int slot) {
     89   if (slot >= module_getNumberSlots(module)) {
     90     return -EINVAL;
     91   } else if (avb_ab_mark_slot_unbootable(ops->ab_ops, slot) ==
     92              AVB_IO_RESULT_OK) {
     93     return 0;
     94   } else {
     95     return -EIO;
     96   }
     97 }
     98 
     99 static int module_isSlotBootable(struct boot_control_module* module,
    100                                  unsigned int slot) {
    101   AvbABData ab_data;
    102   bool is_bootable;
    103 
    104   avb_assert(slot < 2);
    105 
    106   if (slot >= module_getNumberSlots(module)) {
    107     return -EINVAL;
    108   } else if (avb_ab_data_read(ops->ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
    109     return -EIO;
    110   }
    111 
    112   is_bootable = (ab_data.slots[slot].priority > 0) &&
    113                 (ab_data.slots[slot].successful_boot ||
    114                  (ab_data.slots[slot].tries_remaining > 0));
    115 
    116   return is_bootable ? 1 : 0;
    117 }
    118 
    119 static int module_isSlotMarkedSuccessful(struct boot_control_module* module,
    120                                          unsigned int slot) {
    121   AvbABData ab_data;
    122   bool is_marked_successful;
    123 
    124   avb_assert(slot < 2);
    125 
    126   if (slot >= module_getNumberSlots(module)) {
    127     return -EINVAL;
    128   } else if (avb_ab_data_read(ops->ab_ops, &ab_data) != AVB_IO_RESULT_OK) {
    129     return -EIO;
    130   }
    131 
    132   is_marked_successful = ab_data.slots[slot].successful_boot;
    133 
    134   return is_marked_successful ? 1 : 0;
    135 }
    136 
    137 static const char* module_getSuffix(boot_control_module_t* module,
    138                                     unsigned int slot) {
    139   static const char* suffix[2] = {"_a", "_b"};
    140   if (slot >= 2) {
    141     return NULL;
    142   }
    143   return suffix[slot];
    144 }
    145 
    146 static struct hw_module_methods_t module_methods = {
    147     .open = NULL,
    148 };
    149 
    150 boot_control_module_t HAL_MODULE_INFO_SYM = {
    151     .common =
    152         {
    153             .tag = HARDWARE_MODULE_TAG,
    154             .module_api_version = BOOT_CONTROL_MODULE_API_VERSION_0_1,
    155             .hal_api_version = HARDWARE_HAL_API_VERSION,
    156             .id = BOOT_CONTROL_HARDWARE_MODULE_ID,
    157             .name = "AVB implementation of boot_control HAL",
    158             .author = "The Android Open Source Project",
    159             .methods = &module_methods,
    160         },
    161     .init = module_init,
    162     .getNumberSlots = module_getNumberSlots,
    163     .getCurrentSlot = module_getCurrentSlot,
    164     .markBootSuccessful = module_markBootSuccessful,
    165     .setActiveBootSlot = module_setActiveBootSlot,
    166     .setSlotAsUnbootable = module_setSlotAsUnbootable,
    167     .isSlotBootable = module_isSlotBootable,
    168     .getSuffix = module_getSuffix,
    169     .isSlotMarkedSuccessful = module_isSlotMarkedSuccessful,
    170 };
    171