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