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; }
GetActiveBootSlot()86   Slot GetActiveBootSlot() override { return kInvalidSlot; }
87 
MarkBootSuccessfulAsync(base::Callback<void (bool)> callback)88   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override {
89     // We run the callback directly from here to avoid having to setup a message
90     // loop in the test environment.
91     is_marked_successful_[GetCurrentSlot()] = true;
92     callback.Run(true);
93     return true;
94   }
95 
IsSlotMarkedSuccessful(Slot slot)96   bool IsSlotMarkedSuccessful(Slot slot) const override {
97     return slot < num_slots_ && is_marked_successful_[slot];
98   }
99 
100   // Setters
SetNumSlots(unsigned int num_slots)101   void SetNumSlots(unsigned int num_slots) {
102     num_slots_ = num_slots;
103     is_bootable_.resize(num_slots_, false);
104     is_marked_successful_.resize(num_slots_, false);
105     devices_.resize(num_slots_);
106   }
107 
SetCurrentSlot(BootControlInterface::Slot slot)108   void SetCurrentSlot(BootControlInterface::Slot slot) { current_slot_ = slot; }
109 
SetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,const std::string & device)110   void SetPartitionDevice(const std::string& partition_name,
111                           BootControlInterface::Slot slot,
112                           const std::string& device) {
113     DCHECK(slot < num_slots_);
114     devices_[slot][partition_name] = device;
115   }
116 
SetSlotBootable(BootControlInterface::Slot slot,bool bootable)117   void SetSlotBootable(BootControlInterface::Slot slot, bool bootable) {
118     DCHECK(slot < num_slots_);
119     is_bootable_[slot] = bootable;
120   }
121 
GetDynamicPartitionControl()122   DynamicPartitionControlInterface* GetDynamicPartitionControl() override {
123     return dynamic_partition_control_.get();
124   }
125 
126   std::optional<PartitionDevice> GetPartitionDevice(
127       const std::string& partition_name,
128       uint32_t slot,
129       uint32_t current_slot,
130       bool not_in_payload = false) const override {
131     if (slot >= devices_.size()) {
132       return {};
133     }
134     auto device_path = devices_[slot].find(partition_name);
135     if (device_path == devices_[slot].end()) {
136       return {};
137     }
138     PartitionDevice device;
139     device.is_dynamic = false;
140     device.rw_device_path = device_path->second;
141     device.readonly_device_path = device.rw_device_path;
142     return device;
143   }
144 
145  private:
146   BootControlInterface::Slot num_slots_{2};
147   BootControlInterface::Slot current_slot_{0};
148 
149   std::vector<bool> is_bootable_;
150   std::vector<bool> is_marked_successful_;
151   std::vector<std::map<std::string, std::string>> devices_;
152 
153   std::unique_ptr<DynamicPartitionControlInterface> dynamic_partition_control_;
154 
155   DISALLOW_COPY_AND_ASSIGN(FakeBootControl);
156 };
157 
158 }  // namespace chromeos_update_engine
159 
160 #endif  // UPDATE_ENGINE_COMMON_FAKE_BOOT_CONTROL_H_
161