• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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