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 SetDynamicPartitionControl(std::unique_ptr<DynamicPartitionControlInterface> dynamic_control)43 void SetDynamicPartitionControl( 44 std::unique_ptr<DynamicPartitionControlInterface> dynamic_control) { 45 dynamic_partition_control_ = std::move(dynamic_control); 46 } 47 48 // BootControlInterface overrides. GetNumSlots()49 unsigned int GetNumSlots() const override { return num_slots_; } GetCurrentSlot()50 BootControlInterface::Slot GetCurrentSlot() const override { 51 return current_slot_; 52 } 53 GetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,bool not_in_payload,std::string * device,bool * is_dynamic)54 bool GetPartitionDevice(const std::string& partition_name, 55 BootControlInterface::Slot slot, 56 bool not_in_payload, 57 std::string* device, 58 bool* is_dynamic) const override { 59 auto dev = 60 GetPartitionDevice(partition_name, slot, current_slot_, not_in_payload); 61 if (!dev.has_value()) { 62 return false; 63 } 64 if (is_dynamic) { 65 *is_dynamic = dev->is_dynamic; 66 } 67 if (device) { 68 *device = dev->rw_device_path; 69 } 70 return true; 71 } 72 GetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,std::string * device)73 bool GetPartitionDevice(const std::string& partition_name, 74 BootControlInterface::Slot slot, 75 std::string* device) const override { 76 return GetPartitionDevice(partition_name, slot, false, device, nullptr); 77 } 78 IsSlotBootable(BootControlInterface::Slot slot)79 bool IsSlotBootable(BootControlInterface::Slot slot) const override { 80 return slot < num_slots_ && is_bootable_[slot]; 81 } 82 MarkSlotUnbootable(BootControlInterface::Slot slot)83 bool MarkSlotUnbootable(BootControlInterface::Slot slot) override { 84 if (slot >= num_slots_) 85 return false; 86 is_bootable_[slot] = false; 87 return true; 88 } 89 SetActiveBootSlot(Slot slot)90 bool SetActiveBootSlot(Slot slot) override { return true; } GetActiveBootSlot()91 Slot GetActiveBootSlot() override { return kInvalidSlot; } 92 MarkBootSuccessfulAsync(base::Callback<void (bool)> callback)93 bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override { 94 // We run the callback directly from here to avoid having to setup a message 95 // loop in the test environment. 96 is_marked_successful_[GetCurrentSlot()] = true; 97 callback.Run(true); 98 return true; 99 } 100 IsSlotMarkedSuccessful(Slot slot)101 bool IsSlotMarkedSuccessful(Slot slot) const override { 102 return slot < num_slots_ && is_marked_successful_[slot]; 103 } 104 105 // Setters SetNumSlots(unsigned int num_slots)106 void SetNumSlots(unsigned int num_slots) { 107 num_slots_ = num_slots; 108 is_bootable_.resize(num_slots_, false); 109 is_marked_successful_.resize(num_slots_, false); 110 devices_.resize(num_slots_); 111 } 112 SetCurrentSlot(BootControlInterface::Slot slot)113 void SetCurrentSlot(BootControlInterface::Slot slot) { current_slot_ = slot; } 114 SetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,const std::string & device)115 void SetPartitionDevice(const std::string& partition_name, 116 BootControlInterface::Slot slot, 117 const std::string& device) { 118 DCHECK(slot < num_slots_); 119 devices_[slot][partition_name] = device; 120 } 121 SetSlotBootable(BootControlInterface::Slot slot,bool bootable)122 void SetSlotBootable(BootControlInterface::Slot slot, bool bootable) { 123 DCHECK(slot < num_slots_); 124 is_bootable_[slot] = bootable; 125 } 126 GetDynamicPartitionControl()127 DynamicPartitionControlInterface* GetDynamicPartitionControl() override { 128 return dynamic_partition_control_.get(); 129 } 130 131 std::optional<PartitionDevice> GetPartitionDevice( 132 const std::string& partition_name, 133 uint32_t slot, 134 uint32_t current_slot, 135 bool not_in_payload = false) const override { 136 if (slot >= devices_.size()) { 137 return {}; 138 } 139 auto device_path = devices_[slot].find(partition_name); 140 if (device_path == devices_[slot].end()) { 141 return {}; 142 } 143 PartitionDevice device; 144 device.is_dynamic = false; 145 device.rw_device_path = device_path->second; 146 device.readonly_device_path = device.rw_device_path; 147 return device; 148 } 149 150 private: 151 BootControlInterface::Slot num_slots_{2}; 152 BootControlInterface::Slot current_slot_{0}; 153 154 std::vector<bool> is_bootable_; 155 std::vector<bool> is_marked_successful_; 156 std::vector<std::map<std::string, std::string>> devices_; 157 158 std::unique_ptr<DynamicPartitionControlInterface> dynamic_partition_control_; 159 160 DISALLOW_COPY_AND_ASSIGN(FakeBootControl); 161 }; 162 163 } // namespace chromeos_update_engine 164 165 #endif // UPDATE_ENGINE_COMMON_FAKE_BOOT_CONTROL_H_ 166