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 <android/hardware/boot/1.2/IBootControl.h>
24 #include <base/bind.h>
25 #include <base/logging.h>
26 #include <bootloader_message/bootloader_message.h>
27 #include <brillo/message_loops/message_loop.h>
28
29 #include "update_engine/aosp/dynamic_partition_control_android.h"
30 #include "update_engine/common/utils.h"
31
32 using std::string;
33
34 using android::hardware::Return;
35 using android::hardware::boot::V1_0::BoolResult;
36 using android::hardware::boot::V1_0::CommandResult;
37 using android::hardware::boot::V1_0::IBootControl;
38 using Slot = chromeos_update_engine::BootControlInterface::Slot;
39
40 namespace {
41
StoreResultCallback(CommandResult * dest)42 auto StoreResultCallback(CommandResult* dest) {
43 return [dest](const CommandResult& result) { *dest = result; };
44 }
45 } // namespace
46
47 namespace chromeos_update_engine {
48
49 namespace boot_control {
50
51 // Factory defined in boot_control.h.
CreateBootControl()52 std::unique_ptr<BootControlInterface> CreateBootControl() {
53 auto boot_control = std::make_unique<BootControlAndroid>();
54 if (!boot_control->Init()) {
55 return nullptr;
56 }
57 return std::move(boot_control);
58 }
59
60 } // namespace boot_control
61
Init()62 bool BootControlAndroid::Init() {
63 module_ = IBootControl::getService();
64 if (module_ == nullptr) {
65 LOG(ERROR) << "Error getting bootctrl HIDL module.";
66 return false;
67 }
68
69 LOG(INFO) << "Loaded boot control hidl hal.";
70
71 dynamic_control_ =
72 std::make_unique<DynamicPartitionControlAndroid>(GetCurrentSlot());
73
74 return true;
75 }
76
GetNumSlots() const77 unsigned int BootControlAndroid::GetNumSlots() const {
78 return module_->getNumberSlots();
79 }
80
GetCurrentSlot() const81 BootControlInterface::Slot BootControlAndroid::GetCurrentSlot() const {
82 return module_->getCurrentSlot();
83 }
84
GetPartitionDevice(const std::string & partition_name,BootControlInterface::Slot slot,bool not_in_payload,std::string * device,bool * is_dynamic) const85 bool BootControlAndroid::GetPartitionDevice(const std::string& partition_name,
86 BootControlInterface::Slot slot,
87 bool not_in_payload,
88 std::string* device,
89 bool* is_dynamic) const {
90 return dynamic_control_->GetPartitionDevice(partition_name,
91 slot,
92 GetCurrentSlot(),
93 not_in_payload,
94 device,
95 is_dynamic);
96 }
97
GetPartitionDevice(const string & partition_name,BootControlInterface::Slot slot,string * device) const98 bool BootControlAndroid::GetPartitionDevice(const string& partition_name,
99 BootControlInterface::Slot slot,
100 string* device) const {
101 return GetPartitionDevice(
102 partition_name, slot, false /* not_in_payload */, device, nullptr);
103 }
104
IsSlotBootable(Slot slot) const105 bool BootControlAndroid::IsSlotBootable(Slot slot) const {
106 Return<BoolResult> ret = module_->isSlotBootable(slot);
107 if (!ret.isOk()) {
108 LOG(ERROR) << "Unable to determine if slot " << SlotName(slot)
109 << " is bootable: " << ret.description();
110 return false;
111 }
112 if (ret == BoolResult::INVALID_SLOT) {
113 LOG(ERROR) << "Invalid slot: " << SlotName(slot);
114 return false;
115 }
116 return ret == BoolResult::TRUE;
117 }
118
MarkSlotUnbootable(Slot slot)119 bool BootControlAndroid::MarkSlotUnbootable(Slot slot) {
120 CommandResult result;
121 auto ret = module_->setSlotAsUnbootable(slot, StoreResultCallback(&result));
122 if (!ret.isOk()) {
123 LOG(ERROR) << "Unable to call MarkSlotUnbootable for slot "
124 << SlotName(slot) << ": " << ret.description();
125 return false;
126 }
127 if (!result.success) {
128 LOG(ERROR) << "Unable to mark slot " << SlotName(slot)
129 << " as unbootable: " << result.errMsg.c_str();
130 }
131 return result.success;
132 }
133
SetActiveBootSlot(Slot slot)134 bool BootControlAndroid::SetActiveBootSlot(Slot slot) {
135 CommandResult result;
136 auto ret = module_->setActiveBootSlot(slot, StoreResultCallback(&result));
137 if (!ret.isOk()) {
138 LOG(ERROR) << "Unable to call SetActiveBootSlot for slot " << SlotName(slot)
139 << ": " << ret.description();
140 return false;
141 }
142 if (!result.success) {
143 LOG(ERROR) << "Unable to set the active slot to slot " << SlotName(slot)
144 << ": " << result.errMsg.c_str();
145 }
146 return result.success;
147 }
148
MarkBootSuccessfulAsync(base::Callback<void (bool)> callback)149 bool BootControlAndroid::MarkBootSuccessfulAsync(
150 base::Callback<void(bool)> callback) {
151 CommandResult result;
152 auto ret = module_->markBootSuccessful(StoreResultCallback(&result));
153 if (!ret.isOk()) {
154 LOG(ERROR) << "Unable to call MarkBootSuccessful: " << ret.description();
155 return false;
156 }
157 if (!result.success) {
158 LOG(ERROR) << "Unable to mark boot successful: " << result.errMsg.c_str();
159 }
160 return brillo::MessageLoop::current()->PostTask(
161 FROM_HERE, base::Bind(callback, result.success)) !=
162 brillo::MessageLoop::kTaskIdNull;
163 }
164
IsSlotMarkedSuccessful(BootControlInterface::Slot slot) const165 bool BootControlAndroid::IsSlotMarkedSuccessful(
166 BootControlInterface::Slot slot) const {
167 Return<BoolResult> ret = module_->isSlotMarkedSuccessful(slot);
168 CommandResult result;
169 if (!ret.isOk()) {
170 LOG(ERROR) << "Unable to determine if slot " << SlotName(slot)
171 << " is marked successful: " << ret.description();
172 return false;
173 }
174 if (ret == BoolResult::INVALID_SLOT) {
175 LOG(ERROR) << "Invalid slot: " << SlotName(slot);
176 return false;
177 }
178 return ret == BoolResult::TRUE;
179 }
180
GetActiveBootSlot()181 Slot BootControlAndroid::GetActiveBootSlot() {
182 namespace V1_2 = android::hardware::boot::V1_2;
183 using android::sp;
184 sp<V1_2::IBootControl> v1_2_module = V1_2::IBootControl::castFrom(module_);
185 if (v1_2_module != nullptr) {
186 return v1_2_module->getActiveBootSlot();
187 }
188 LOG(WARNING) << "BootControl module version is lower than 1.2, "
189 << __FUNCTION__ << " failed";
190 return kInvalidSlot;
191 }
192
193 DynamicPartitionControlInterface*
GetDynamicPartitionControl()194 BootControlAndroid::GetDynamicPartitionControl() {
195 return dynamic_control_.get();
196 }
197
GetPartitionDevice(const std::string & partition_name,uint32_t slot,uint32_t current_slot,bool not_in_payload) const198 std::optional<PartitionDevice> BootControlAndroid::GetPartitionDevice(
199 const std::string& partition_name,
200 uint32_t slot,
201 uint32_t current_slot,
202 bool not_in_payload) const {
203 return dynamic_control_->GetPartitionDevice(
204 partition_name, slot, current_slot, not_in_payload);
205 }
206 } // namespace chromeos_update_engine
207