blob: 12296d7e981a5c975d5218af5ea0bbbd3d28b518 [file] [log] [blame]
Alex Deymob17327c2015-09-04 10:29:00 -07001//
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
Alex Deymo1b03f9f2015-12-09 00:38:36 -080017#include "update_engine/boot_control_android.h"
Alex Deymob17327c2015-09-04 10:29:00 -070018
Sen Jiangd944faa2018-08-22 18:46:39 -070019#include <memory>
20#include <utility>
Yifan Hongd4db07e2018-10-18 17:46:27 -070021#include <vector>
Sen Jiangd944faa2018-08-22 18:46:39 -070022
Alex Deymoaa26f622015-09-16 18:21:27 -070023#include <base/bind.h>
Alex Deymoaa26f622015-09-16 18:21:27 -070024#include <base/logging.h>
Yifan Hongd4db07e2018-10-18 17:46:27 -070025#include <base/strings/string_util.h>
Sen Jiangd944faa2018-08-22 18:46:39 -070026#include <bootloader_message/bootloader_message.h>
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070027#include <brillo/message_loops/message_loop.h>
David Andersond63cb3c2018-10-01 14:15:00 -070028#include <fs_mgr.h>
Alex Deymob17327c2015-09-04 10:29:00 -070029
Alex Deymo39910dc2015-11-09 17:04:30 -080030#include "update_engine/common/utils.h"
Yifan Hong537802d2018-08-15 13:15:42 -070031#include "update_engine/dynamic_partition_control_android.h"
Alex Deymob17327c2015-09-04 10:29:00 -070032
33using std::string;
34
Yifan Hong537802d2018-08-15 13:15:42 -070035using android::dm::DmDeviceState;
Yifan Hong537802d2018-08-15 13:15:42 -070036using android::fs_mgr::Partition;
Yifan Hong537802d2018-08-15 13:15:42 -070037using android::hardware::hidl_string;
Connor O'Briencee6ad92016-11-21 13:53:52 -080038using android::hardware::Return;
39using android::hardware::boot::V1_0::BoolResult;
40using android::hardware::boot::V1_0::CommandResult;
41using android::hardware::boot::V1_0::IBootControl;
Yifan Hong537802d2018-08-15 13:15:42 -070042using Slot = chromeos_update_engine::BootControlInterface::Slot;
Yifan Hong6b0a9842018-10-16 16:54:18 -070043using PartitionMetadata =
44 chromeos_update_engine::BootControlInterface::PartitionMetadata;
Connor O'Briencee6ad92016-11-21 13:53:52 -080045
46namespace {
Yifan Hong537802d2018-08-15 13:15:42 -070047
Connor O'Briencee6ad92016-11-21 13:53:52 -080048auto StoreResultCallback(CommandResult* dest) {
49 return [dest](const CommandResult& result) { *dest = result; };
50}
51} // namespace
Alex Deymo44348e02016-07-29 16:22:26 -070052
Alex Deymob17327c2015-09-04 10:29:00 -070053namespace chromeos_update_engine {
54
55namespace boot_control {
56
57// Factory defined in boot_control.h.
58std::unique_ptr<BootControlInterface> CreateBootControl() {
Yifan Hong537802d2018-08-15 13:15:42 -070059 auto boot_control = std::make_unique<BootControlAndroid>();
David Zeuthen753fadc2015-09-15 16:34:09 -040060 if (!boot_control->Init()) {
61 return nullptr;
62 }
Alex Vakulenkoce8c8ee2016-04-08 08:59:26 -070063 return std::move(boot_control);
Alex Deymob17327c2015-09-04 10:29:00 -070064}
65
66} // namespace boot_control
67
David Zeuthen753fadc2015-09-15 16:34:09 -040068bool BootControlAndroid::Init() {
Chris Phoenixafde8e82017-01-17 23:14:58 -080069 module_ = IBootControl::getService();
Connor O'Briencee6ad92016-11-21 13:53:52 -080070 if (module_ == nullptr) {
Steven Moreland927e00d2017-01-04 12:58:40 -080071 LOG(ERROR) << "Error getting bootctrl HIDL module.";
David Zeuthen753fadc2015-09-15 16:34:09 -040072 return false;
73 }
74
Steven Moreland927e00d2017-01-04 12:58:40 -080075 LOG(INFO) << "Loaded boot control hidl hal.";
David Zeuthen753fadc2015-09-15 16:34:09 -040076
Yifan Hong537802d2018-08-15 13:15:42 -070077 dynamic_control_ = std::make_unique<DynamicPartitionControlAndroid>();
78
David Zeuthen753fadc2015-09-15 16:34:09 -040079 return true;
80}
Alex Deymob17327c2015-09-04 10:29:00 -070081
Yifan Hong537802d2018-08-15 13:15:42 -070082void BootControlAndroid::Cleanup() {
83 dynamic_control_->Cleanup();
84}
85
Alex Deymob17327c2015-09-04 10:29:00 -070086unsigned int BootControlAndroid::GetNumSlots() const {
Connor O'Briencee6ad92016-11-21 13:53:52 -080087 return module_->getNumberSlots();
Alex Deymob17327c2015-09-04 10:29:00 -070088}
89
90BootControlInterface::Slot BootControlAndroid::GetCurrentSlot() const {
Connor O'Briencee6ad92016-11-21 13:53:52 -080091 return module_->getCurrentSlot();
Alex Deymob17327c2015-09-04 10:29:00 -070092}
93
Yifan Hong537802d2018-08-15 13:15:42 -070094bool BootControlAndroid::GetSuffix(Slot slot, string* suffix) const {
Connor O'Briencee6ad92016-11-21 13:53:52 -080095 auto store_suffix_cb = [&suffix](hidl_string cb_suffix) {
Yifan Hong537802d2018-08-15 13:15:42 -070096 *suffix = cb_suffix.c_str();
Connor O'Briencee6ad92016-11-21 13:53:52 -080097 };
98 Return<void> ret = module_->getSuffix(slot, store_suffix_cb);
99
Yifan Hong7b514b42016-12-21 13:02:00 -0800100 if (!ret.isOk()) {
Alex Deymo31d95ac2015-09-17 11:56:18 -0700101 LOG(ERROR) << "boot_control impl returned no suffix for slot "
102 << SlotName(slot);
David Zeuthen753fadc2015-09-15 16:34:09 -0400103 return false;
104 }
Yifan Hong537802d2018-08-15 13:15:42 -0700105 return true;
106}
107
108bool BootControlAndroid::GetPartitionDevice(const string& partition_name,
109 Slot slot,
110 string* device) const {
111 string suffix;
112 if (!GetSuffix(slot, &suffix)) {
113 return false;
114 }
115
116 const string target_partition_name = partition_name + suffix;
117
118 // DeltaPerformer calls InitPartitionMetadata before calling
119 // InstallPlan::LoadPartitionsFromSlots. After InitPartitionMetadata,
120 // the partition must be re-mapped with force_writable == true. Hence,
121 // we only need to check device mapper.
122 if (dynamic_control_->IsDynamicPartitionsEnabled()) {
123 switch (dynamic_control_->GetState(target_partition_name)) {
124 case DmDeviceState::ACTIVE:
125 if (dynamic_control_->GetDmDevicePathByName(target_partition_name,
126 device)) {
127 LOG(INFO) << target_partition_name
128 << " is mapped on device mapper: " << *device;
129 return true;
130 }
131 LOG(ERROR) << target_partition_name
132 << " is mapped but path is unknown.";
133 return false;
134
135 case DmDeviceState::INVALID:
136 // Try static partitions.
137 break;
138
139 case DmDeviceState::SUSPENDED: // fallthrough
140 default:
141 LOG(ERROR) << target_partition_name
142 << " is mapped on device mapper but state is unknown";
143 return false;
144 }
145 }
146
147 string device_dir_str;
148 if (!dynamic_control_->GetDeviceDir(&device_dir_str)) {
149 return false;
150 }
David Zeuthen753fadc2015-09-15 16:34:09 -0400151
Sen Jiangd944faa2018-08-22 18:46:39 -0700152 base::FilePath path =
Yifan Hong537802d2018-08-15 13:15:42 -0700153 base::FilePath(device_dir_str).Append(target_partition_name);
154 if (!dynamic_control_->DeviceExists(path.value())) {
David Zeuthen753fadc2015-09-15 16:34:09 -0400155 LOG(ERROR) << "Device file " << path.value() << " does not exist.";
156 return false;
157 }
158
159 *device = path.value();
160 return true;
Alex Deymob17327c2015-09-04 10:29:00 -0700161}
162
163bool BootControlAndroid::IsSlotBootable(Slot slot) const {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800164 Return<BoolResult> ret = module_->isSlotBootable(slot);
Yifan Hong7b514b42016-12-21 13:02:00 -0800165 if (!ret.isOk()) {
Alex Deymo31d95ac2015-09-17 11:56:18 -0700166 LOG(ERROR) << "Unable to determine if slot " << SlotName(slot)
Connor O'Briencee6ad92016-11-21 13:53:52 -0800167 << " is bootable: "
Yifan Hong7b514b42016-12-21 13:02:00 -0800168 << ret.description();
David Zeuthen753fadc2015-09-15 16:34:09 -0400169 return false;
170 }
Connor O'Briencee6ad92016-11-21 13:53:52 -0800171 if (ret == BoolResult::INVALID_SLOT) {
172 LOG(ERROR) << "Invalid slot: " << SlotName(slot);
173 return false;
174 }
175 return ret == BoolResult::TRUE;
Alex Deymob17327c2015-09-04 10:29:00 -0700176}
177
178bool BootControlAndroid::MarkSlotUnbootable(Slot slot) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800179 CommandResult result;
180 auto ret = module_->setSlotAsUnbootable(slot, StoreResultCallback(&result));
Yifan Hong7b514b42016-12-21 13:02:00 -0800181 if (!ret.isOk()) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800182 LOG(ERROR) << "Unable to call MarkSlotUnbootable for slot "
183 << SlotName(slot) << ": "
Yifan Hong7b514b42016-12-21 13:02:00 -0800184 << ret.description();
David Zeuthen753fadc2015-09-15 16:34:09 -0400185 return false;
186 }
Connor O'Briencee6ad92016-11-21 13:53:52 -0800187 if (!result.success) {
188 LOG(ERROR) << "Unable to mark slot " << SlotName(slot)
189 << " as unbootable: " << result.errMsg.c_str();
190 }
191 return result.success;
Alex Deymob17327c2015-09-04 10:29:00 -0700192}
193
Alex Deymo31d95ac2015-09-17 11:56:18 -0700194bool BootControlAndroid::SetActiveBootSlot(Slot slot) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800195 CommandResult result;
196 auto ret = module_->setActiveBootSlot(slot, StoreResultCallback(&result));
Yifan Hong7b514b42016-12-21 13:02:00 -0800197 if (!ret.isOk()) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800198 LOG(ERROR) << "Unable to call SetActiveBootSlot for slot " << SlotName(slot)
Yifan Hong7b514b42016-12-21 13:02:00 -0800199 << ": " << ret.description();
Connor O'Briencee6ad92016-11-21 13:53:52 -0800200 return false;
Alex Deymo29dcbf32016-10-06 13:33:20 -0700201 }
Connor O'Briencee6ad92016-11-21 13:53:52 -0800202 if (!result.success) {
203 LOG(ERROR) << "Unable to set the active slot to slot " << SlotName(slot)
204 << ": " << result.errMsg.c_str();
205 }
206 return result.success;
Alex Deymo31d95ac2015-09-17 11:56:18 -0700207}
208
Alex Deymoaa26f622015-09-16 18:21:27 -0700209bool BootControlAndroid::MarkBootSuccessfulAsync(
210 base::Callback<void(bool)> callback) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800211 CommandResult result;
212 auto ret = module_->markBootSuccessful(StoreResultCallback(&result));
Yifan Hong7b514b42016-12-21 13:02:00 -0800213 if (!ret.isOk()) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800214 LOG(ERROR) << "Unable to call MarkBootSuccessful: "
Yifan Hong7b514b42016-12-21 13:02:00 -0800215 << ret.description();
Connor O'Briencee6ad92016-11-21 13:53:52 -0800216 return false;
217 }
218 if (!result.success) {
219 LOG(ERROR) << "Unable to mark boot successful: " << result.errMsg.c_str();
Alex Deymoaa26f622015-09-16 18:21:27 -0700220 }
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700221 return brillo::MessageLoop::current()->PostTask(
Connor O'Briencee6ad92016-11-21 13:53:52 -0800222 FROM_HERE, base::Bind(callback, result.success)) !=
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700223 brillo::MessageLoop::kTaskIdNull;
Alex Deymoaa26f622015-09-16 18:21:27 -0700224}
225
Yifan Hong537802d2018-08-15 13:15:42 -0700226namespace {
227
Yifan Hongd4db07e2018-10-18 17:46:27 -0700228bool InitPartitionMetadataInternal(
229 DynamicPartitionControlInterface* dynamic_control,
230 const string& super_device,
231 Slot source_slot,
232 Slot target_slot,
233 const string& target_suffix,
234 const PartitionMetadata& partition_metadata) {
235 auto builder =
236 dynamic_control->LoadMetadataBuilder(super_device, source_slot);
237 if (builder == nullptr) {
238 // TODO(elsk): allow reconstructing metadata from partition_metadata
239 // in recovery sideload.
240 LOG(ERROR) << "No metadata at "
241 << BootControlInterface::SlotName(source_slot);
Yifan Hong537802d2018-08-15 13:15:42 -0700242 return false;
243 }
244
Yifan Hongd4db07e2018-10-18 17:46:27 -0700245 std::vector<string> groups = builder->ListGroups();
246 for (const auto& group_name : groups) {
247 if (base::EndsWith(
248 group_name, target_suffix, base::CompareCase::SENSITIVE)) {
249 LOG(INFO) << "Removing group " << group_name;
250 builder->RemoveGroupAndPartitions(group_name);
251 }
252 }
253
254 uint64_t total_size = 0;
255 for (const auto& group : partition_metadata.groups) {
256 total_size += group.size;
257 }
258
259 if (total_size > (builder->AllocatableSpace() / 2)) {
260 LOG(ERROR)
261 << "The maximum size of all groups with suffix " << target_suffix
262 << " (" << total_size
263 << ") has exceeded half of allocatable space for dynamic partitions "
264 << (builder->AllocatableSpace() / 2) << ".";
Yifan Hong537802d2018-08-15 13:15:42 -0700265 return false;
266 }
267
Yifan Hongd4db07e2018-10-18 17:46:27 -0700268 for (const auto& group : partition_metadata.groups) {
269 auto group_name_suffix = group.name + target_suffix;
270 if (!builder->AddGroup(group_name_suffix, group.size)) {
271 LOG(ERROR) << "Cannot add group " << group_name_suffix << " with size "
272 << group.size;
273 return false;
274 }
275 LOG(INFO) << "Added group " << group_name_suffix << " with size "
276 << group.size;
277
278 for (const auto& partition : group.partitions) {
279 auto parition_name_suffix = partition.name + target_suffix;
280 Partition* p = builder->AddPartition(
281 parition_name_suffix, group_name_suffix, LP_PARTITION_ATTR_READONLY);
282 if (!p) {
283 LOG(ERROR) << "Cannot add partition " << parition_name_suffix
284 << " to group " << group_name_suffix;
285 return false;
286 }
287 if (!builder->ResizePartition(p, partition.size)) {
288 LOG(ERROR) << "Cannot resize partition " << parition_name_suffix
289 << " to size " << partition.size << ". Not enough space?";
290 return false;
291 }
292 LOG(INFO) << "Added partition " << parition_name_suffix << " to group "
293 << group_name_suffix << " with size " << partition.size;
294 }
Yifan Hong537802d2018-08-15 13:15:42 -0700295 }
296
Yifan Hongd4db07e2018-10-18 17:46:27 -0700297 return dynamic_control->StoreMetadata(
298 super_device, builder.get(), target_slot);
Yifan Hong537802d2018-08-15 13:15:42 -0700299}
300
Yifan Hongaf65ef12018-10-29 11:09:06 -0700301// Unmap all partitions, and remap partitions as writable.
Yifan Hongd4db07e2018-10-18 17:46:27 -0700302bool Remap(DynamicPartitionControlInterface* dynamic_control,
303 const string& super_device,
304 Slot target_slot,
305 const string& target_suffix,
306 const PartitionMetadata& partition_metadata) {
307 for (const auto& group : partition_metadata.groups) {
308 for (const auto& partition : group.partitions) {
309 if (!dynamic_control->UnmapPartitionOnDeviceMapper(
310 partition.name + target_suffix, true /* wait */)) {
311 return false;
312 }
313 if (partition.size == 0) {
314 continue;
315 }
316 string map_path;
317 if (!dynamic_control->MapPartitionOnDeviceMapper(
318 super_device,
319 partition.name + target_suffix,
320 target_slot,
Yifan Hongaf65ef12018-10-29 11:09:06 -0700321 true /* force writable */,
Yifan Hongd4db07e2018-10-18 17:46:27 -0700322 &map_path)) {
Yifan Hong537802d2018-08-15 13:15:42 -0700323 return false;
324 }
325 }
Yifan Hong537802d2018-08-15 13:15:42 -0700326 }
327 return true;
328}
329
Yifan Hong537802d2018-08-15 13:15:42 -0700330} // namespace
331
332bool BootControlAndroid::InitPartitionMetadata(
Yifan Hong6b0a9842018-10-16 16:54:18 -0700333 Slot target_slot, const PartitionMetadata& partition_metadata) {
Yifan Hong537802d2018-08-15 13:15:42 -0700334 if (!dynamic_control_->IsDynamicPartitionsEnabled()) {
335 return true;
336 }
337
338 string device_dir_str;
339 if (!dynamic_control_->GetDeviceDir(&device_dir_str)) {
340 return false;
341 }
342 base::FilePath device_dir(device_dir_str);
David Andersond63cb3c2018-10-01 14:15:00 -0700343 string super_device =
344 device_dir.Append(fs_mgr_get_super_partition_name()).value();
Yifan Hong537802d2018-08-15 13:15:42 -0700345
346 Slot current_slot = GetCurrentSlot();
347 if (target_slot == current_slot) {
348 LOG(ERROR) << "Cannot call InitPartitionMetadata on current slot.";
349 return false;
350 }
351
Yifan Hong537802d2018-08-15 13:15:42 -0700352 string target_suffix;
353 if (!GetSuffix(target_slot, &target_suffix)) {
354 return false;
355 }
356
Yifan Hongd4db07e2018-10-18 17:46:27 -0700357 if (!InitPartitionMetadataInternal(dynamic_control_.get(),
358 super_device,
359 current_slot,
360 target_slot,
361 target_suffix,
362 partition_metadata)) {
Yifan Hong537802d2018-08-15 13:15:42 -0700363 return false;
364 }
365
Yifan Hongd4db07e2018-10-18 17:46:27 -0700366 if (!Remap(dynamic_control_.get(),
367 super_device,
368 target_slot,
369 target_suffix,
370 partition_metadata)) {
Yifan Hong537802d2018-08-15 13:15:42 -0700371 return false;
372 }
373
Yifan Hong537802d2018-08-15 13:15:42 -0700374 return true;
375}
376
Alex Deymob17327c2015-09-04 10:29:00 -0700377} // namespace chromeos_update_engine