1 // 2 // Copyright (C) 2015 The Android Open Source Project 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 17 #ifndef UPDATE_ENGINE_COMMON_FAKE_BOOT_CONTROL_H_ 18 #define UPDATE_ENGINE_COMMON_FAKE_BOOT_CONTROL_H_ 19 20 #include <map> 21 #include <memory> 22 #include <string> 23 #include <vector> 24 25 #include <base/time/time.h> 26 27 #include "update_engine/common/boot_control_interface.h" 28 #include "update_engine/common/dynamic_partition_control_stub.h" 29 30 namespace chromeos_update_engine { 31 32 // Implements a fake bootloader control interface used for testing. 33 class FakeBootControl : public BootControlInterface { 34 public: FakeBootControl()35 FakeBootControl() { 36 SetNumSlots(num_slots_); 37 // The current slot should be bootable. 38 is_bootable_[current_slot_] = true; 39 40 dynamic_partition_control_.reset(new DynamicPartitionControlStub()); 41 } 42 43 // BootControlInterface overrides. GetNumSlots()44 unsigned int GetNumSlots() const override { return num_slots_; } GetCurrentSlot()45 BootControlInterface::Slot GetCurrentSlot() const override { 46 return current_slot_; 47 } 48 GetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,bool not_in_payload,std::string * device,bool * is_dynamic)49 bool GetPartitionDevice(const std::string& partition_name, 50 BootControlInterface::Slot slot, 51 bool not_in_payload, 52 std::string* device, 53 bool* is_dynamic) const override { 54 auto dev = 55 GetPartitionDevice(partition_name, slot, current_slot_, not_in_payload); 56 if (!dev.has_value()) { 57 return false; 58 } 59 if (is_dynamic) { 60 *is_dynamic = dev->is_dynamic; 61 } 62 if (device) { 63 *device = dev->rw_device_path; 64 } 65 return true; 66 } 67 GetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,std::string * device)68 bool GetPartitionDevice(const std::string& partition_name, 69 BootControlInterface::Slot slot, 70 std::string* device) const override { 71 return GetPartitionDevice(partition_name, slot, false, device, nullptr); 72 } 73 IsSlotBootable(BootControlInterface::Slot slot)74 bool IsSlotBootable(BootControlInterface::Slot slot) const override { 75 return slot < num_slots_ && is_bootable_[slot]; 76 } 77 MarkSlotUnbootable(BootControlInterface::Slot slot)78 bool MarkSlotUnbootable(BootControlInterface::Slot slot) override { 79 if (slot >= num_slots_) 80 return false; 81 is_bootable_[slot] = false; 82 return true; 83 } 84 SetActiveBootSlot(Slot slot)85 bool SetActiveBootSlot(Slot slot) override { return true; } 86 MarkBootSuccessfulAsync(base::Callback<void (bool)> callback)87 bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override { 88 // We run the callback directly from here to avoid having to setup a message 89 // loop in the test environment. 90 is_marked_successful_[GetCurrentSlot()] = true; 91 callback.Run(true); 92 return true; 93 } 94 IsSlotMarkedSuccessful(Slot slot)95 bool IsSlotMarkedSuccessful(Slot slot) const override { 96 return slot < num_slots_ && is_marked_successful_[slot]; 97 } 98 99 // Setters SetNumSlots(unsigned int num_slots)100 void SetNumSlots(unsigned int num_slots) { 101 num_slots_ = num_slots; 102 is_bootable_.resize(num_slots_, false); 103 is_marked_successful_.resize(num_slots_, false); 104 devices_.resize(num_slots_); 105 } 106 SetCurrentSlot(BootControlInterface::Slot slot)107 void SetCurrentSlot(BootControlInterface::Slot slot) { current_slot_ = slot; } 108 SetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,const std::string & device)109 void SetPartitionDevice(const std::string& partition_name, 110 BootControlInterface::Slot slot, 111 const std::string& device) { 112 DCHECK(slot < num_slots_); 113 devices_[slot][partition_name] = device; 114 } 115 SetSlotBootable(BootControlInterface::Slot slot,bool bootable)116 void SetSlotBootable(BootControlInterface::Slot slot, bool bootable) { 117 DCHECK(slot < num_slots_); 118 is_bootable_[slot] = bootable; 119 } 120 GetDynamicPartitionControl()121 DynamicPartitionControlInterface* GetDynamicPartitionControl() override { 122 return dynamic_partition_control_.get(); 123 } 124 125 std::optional<PartitionDevice> GetPartitionDevice( 126 const std::string& partition_name, 127 uint32_t slot, 128 uint32_t current_slot, 129 bool not_in_payload = false) const override { 130 if (slot >= devices_.size()) { 131 return {}; 132 } 133 auto device_path = devices_[slot].find(partition_name); 134 if (device_path == devices_[slot].end()) { 135 return {}; 136 } 137 PartitionDevice device; 138 device.is_dynamic = false; 139 device.rw_device_path = device_path->second; 140 device.readonly_device_path = device.rw_device_path; 141 return device; 142 } 143 144 private: 145 BootControlInterface::Slot num_slots_{2}; 146 BootControlInterface::Slot current_slot_{0}; 147 148 std::vector<bool> is_bootable_; 149 std::vector<bool> is_marked_successful_; 150 std::vector<std::map<std::string, std::string>> devices_; 151 152 std::unique_ptr<DynamicPartitionControlInterface> dynamic_partition_control_; 153 154 DISALLOW_COPY_AND_ASSIGN(FakeBootControl); 155 }; 156 157 } // namespace chromeos_update_engine 158 159 #endif // UPDATE_ENGINE_COMMON_FAKE_BOOT_CONTROL_H_ 160