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     if (slot >= num_slots_)
55       return false;
56     auto part_it = devices_[slot].find(partition_name);
57     if (part_it == devices_[slot].end())
58       return false;
59     *device = part_it->second;
60     return true;
61   }
62 
GetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,std::string * device)63   bool GetPartitionDevice(const std::string& partition_name,
64                           BootControlInterface::Slot slot,
65                           std::string* device) const override {
66     return GetPartitionDevice(partition_name, slot, false, device, nullptr);
67   }
68 
IsSlotBootable(BootControlInterface::Slot slot)69   bool IsSlotBootable(BootControlInterface::Slot slot) const override {
70     return slot < num_slots_ && is_bootable_[slot];
71   }
72 
MarkSlotUnbootable(BootControlInterface::Slot slot)73   bool MarkSlotUnbootable(BootControlInterface::Slot slot) override {
74     if (slot >= num_slots_)
75       return false;
76     is_bootable_[slot] = false;
77     return true;
78   }
79 
SetActiveBootSlot(Slot slot)80   bool SetActiveBootSlot(Slot slot) override { return true; }
81 
MarkBootSuccessfulAsync(base::Callback<void (bool)> callback)82   bool MarkBootSuccessfulAsync(base::Callback<void(bool)> callback) override {
83     // We run the callback directly from here to avoid having to setup a message
84     // loop in the test environment.
85     is_marked_successful_[GetCurrentSlot()] = true;
86     callback.Run(true);
87     return true;
88   }
89 
IsSlotMarkedSuccessful(Slot slot)90   bool IsSlotMarkedSuccessful(Slot slot) const override {
91     return slot < num_slots_ && is_marked_successful_[slot];
92   }
93 
94   // Setters
SetNumSlots(unsigned int num_slots)95   void SetNumSlots(unsigned int num_slots) {
96     num_slots_ = num_slots;
97     is_bootable_.resize(num_slots_, false);
98     is_marked_successful_.resize(num_slots_, false);
99     devices_.resize(num_slots_);
100   }
101 
SetCurrentSlot(BootControlInterface::Slot slot)102   void SetCurrentSlot(BootControlInterface::Slot slot) { current_slot_ = slot; }
103 
SetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,const std::string & device)104   void SetPartitionDevice(const std::string& partition_name,
105                           BootControlInterface::Slot slot,
106                           const std::string& device) {
107     DCHECK(slot < num_slots_);
108     devices_[slot][partition_name] = device;
109   }
110 
SetSlotBootable(BootControlInterface::Slot slot,bool bootable)111   void SetSlotBootable(BootControlInterface::Slot slot, bool bootable) {
112     DCHECK(slot < num_slots_);
113     is_bootable_[slot] = bootable;
114   }
115 
GetDynamicPartitionControl()116   DynamicPartitionControlInterface* GetDynamicPartitionControl() {
117     return dynamic_partition_control_.get();
118   }
119 
120  private:
121   BootControlInterface::Slot num_slots_{2};
122   BootControlInterface::Slot current_slot_{0};
123 
124   std::vector<bool> is_bootable_;
125   std::vector<bool> is_marked_successful_;
126   std::vector<std::map<std::string, std::string>> devices_;
127 
128   std::unique_ptr<DynamicPartitionControlInterface> dynamic_partition_control_;
129 
130   DISALLOW_COPY_AND_ASSIGN(FakeBootControl);
131 };
132 
133 }  // namespace chromeos_update_engine
134 
135 #endif  // UPDATE_ENGINE_COMMON_FAKE_BOOT_CONTROL_H_
136