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 #include "update_engine/aosp/boot_control_android.h"
18
19 #include <memory>
20 #include <utility>
21 #include <vector>
22
23 #include <base/bind.h>
24 #include <base/logging.h>
25 #include <bootloader_message/bootloader_message.h>
26 #include <brillo/message_loops/message_loop.h>
27
28 #include "update_engine/aosp/dynamic_partition_control_android.h"
29
30 using std::string;
31
32 using Slot = chromeos_update_engine::BootControlInterface::Slot;
33
34 namespace {
35
36 } // namespace
37
38 namespace chromeos_update_engine {
39
40 namespace boot_control {
41
42 // Factory defined in boot_control.h.
CreateBootControl()43 std::unique_ptr<BootControlInterface> CreateBootControl() {
44 auto boot_control = std::make_unique<BootControlAndroid>();
45 if (!boot_control->Init()) {
46 return nullptr;
47 }
48 return std::move(boot_control);
49 }
50
51 } // namespace boot_control
52
53 using android::hal::BootControlClient;
54 using android::hal::CommandResult;
55 using android::hal::BootControlVersion;
56
Init()57 bool BootControlAndroid::Init() {
58 module_ = BootControlClient::WaitForService();
59 if (module_ == nullptr) {
60 LOG(ERROR) << "Error getting bootctrl module.";
61 return false;
62 }
63
64 LOG(INFO) << "Loaded boot control hal.";
65
66 dynamic_control_ =
67 std::make_unique<DynamicPartitionControlAndroid>(GetCurrentSlot());
68
69 return true;
70 }
71
GetNumSlots() const72 unsigned int BootControlAndroid::GetNumSlots() const {
73 return module_->GetNumSlots();
74 }
75
GetCurrentSlot() const76 BootControlInterface::Slot BootControlAndroid::GetCurrentSlot() const {
77 return module_->GetCurrentSlot();
78 }
79
GetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,bool not_in_payload,std::string * device,bool * is_dynamic) const80 bool BootControlAndroid::GetPartitionDevice(const std::string& partition_name,
81 BootControlInterface::Slot slot,
82 bool not_in_payload,
83 std::string* device,
84 bool* is_dynamic) const {
85 return dynamic_control_->GetPartitionDevice(partition_name,
86 slot,
87 GetCurrentSlot(),
88 not_in_payload,
89 device,
90 is_dynamic);
91 }
92
GetPartitionDevice(const string & partition_name,BootControlInterface::Slot slot,string * device) const93 bool BootControlAndroid::GetPartitionDevice(const string& partition_name,
94 BootControlInterface::Slot slot,
95 string* device) const {
96 return GetPartitionDevice(
97 partition_name, slot, false /* not_in_payload */, device, nullptr);
98 }
99
IsSlotBootable(Slot slot) const100 bool BootControlAndroid::IsSlotBootable(Slot slot) const {
101 const auto ret = module_->IsSlotBootable(slot);
102 if (!ret.has_value()) {
103 LOG(ERROR) << "Unable to determine if slot " << SlotName(slot)
104 << " is bootable";
105 return false;
106 }
107 return ret.value();
108 }
109
MarkSlotUnbootable(Slot slot)110 bool BootControlAndroid::MarkSlotUnbootable(Slot slot) {
111 const auto ret = module_->MarkSlotUnbootable(slot);
112 if (!ret.IsOk()) {
113 LOG(ERROR) << "Unable to call MarkSlotUnbootable for slot "
114 << SlotName(slot) << ": " << ret.errMsg;
115 return false;
116 }
117 return ret.success;
118 }
119
SetActiveBootSlot(Slot slot)120 bool BootControlAndroid::SetActiveBootSlot(Slot slot) {
121 const auto result = module_->SetActiveBootSlot(slot);
122 if (!result.IsOk()) {
123 LOG(ERROR) << "Unable to call SetActiveBootSlot for slot " << SlotName(slot)
124 << ": " << result.errMsg;
125 return false;
126 }
127 if (!result.success) {
128 LOG(ERROR) << "Unable to set the active slot to slot " << SlotName(slot)
129 << ": " << result.errMsg.c_str();
130 }
131 return result.success;
132 }
133
MarkBootSuccessfulAsync(base::Callback<void (bool)> callback)134 bool BootControlAndroid::MarkBootSuccessfulAsync(
135 base::Callback<void(bool)> callback) {
136 auto ret = module_->MarkBootSuccessful();
137 if (!ret.IsOk()) {
138 LOG(ERROR) << "Unable to MarkBootSuccessful: " << ret.errMsg;
139 return false;
140 }
141 return brillo::MessageLoop::current()->PostTask(
142 FROM_HERE, base::Bind(callback, ret.success)) !=
143 brillo::MessageLoop::kTaskIdNull;
144 }
145
IsSlotMarkedSuccessful(BootControlInterface::Slot slot) const146 bool BootControlAndroid::IsSlotMarkedSuccessful(
147 BootControlInterface::Slot slot) const {
148 const auto ret = module_->IsSlotMarkedSuccessful(slot);
149 CommandResult result;
150 if (!ret.has_value()) {
151 LOG(ERROR) << "Unable to determine if slot " << SlotName(slot)
152 << " is marked successful";
153 return false;
154 }
155 return ret.value();
156 }
157
GetActiveBootSlot()158 Slot BootControlAndroid::GetActiveBootSlot() {
159 if (module_->GetVersion() >= android::hal::BootControlVersion::BOOTCTL_V1_2) {
160 return module_->GetActiveBootSlot();
161 }
162 LOG(WARNING) << "BootControl module version is lower than 1.2, "
163 << __FUNCTION__ << " failed";
164 return kInvalidSlot;
165 }
166
167 DynamicPartitionControlInterface*
GetDynamicPartitionControl()168 BootControlAndroid::GetDynamicPartitionControl() {
169 return dynamic_control_.get();
170 }
171
GetPartitionDevice(const std::string & partition_name,uint32_t slot,uint32_t current_slot,bool not_in_payload) const172 std::optional<PartitionDevice> BootControlAndroid::GetPartitionDevice(
173 const std::string& partition_name,
174 uint32_t slot,
175 uint32_t current_slot,
176 bool not_in_payload) const {
177 return dynamic_control_->GetPartitionDevice(
178 partition_name, slot, current_slot, not_in_payload);
179 }
180 } // namespace chromeos_update_engine
181