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