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