blob: 4c998b1b8b841037472751ef503b74fc85f7bb4c [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>
Sen Jiangd944faa2018-08-22 18:46:39 -070025#include <bootloader_message/bootloader_message.h>
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -070026#include <brillo/message_loops/message_loop.h>
Mark Salyzyn62b42c82018-12-05 13:33:17 -080027#include <fs_mgr_overlayfs.h>
Yifan Hong700d7c12019-07-23 20:49:16 -070028#include <libdm/dm.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::hardware::hidl_string;
Connor O'Briencee6ad92016-11-21 13:53:52 -080037using android::hardware::Return;
38using android::hardware::boot::V1_0::BoolResult;
39using android::hardware::boot::V1_0::CommandResult;
40using android::hardware::boot::V1_0::IBootControl;
Yifan Hong537802d2018-08-15 13:15:42 -070041using Slot = chromeos_update_engine::BootControlInterface::Slot;
Connor O'Briencee6ad92016-11-21 13:53:52 -080042
43namespace {
Yifan Hong537802d2018-08-15 13:15:42 -070044
Connor O'Briencee6ad92016-11-21 13:53:52 -080045auto StoreResultCallback(CommandResult* dest) {
46 return [dest](const CommandResult& result) { *dest = result; };
47}
48} // namespace
Alex Deymo44348e02016-07-29 16:22:26 -070049
Alex Deymob17327c2015-09-04 10:29:00 -070050namespace chromeos_update_engine {
51
52namespace boot_control {
53
54// Factory defined in boot_control.h.
55std::unique_ptr<BootControlInterface> CreateBootControl() {
Yifan Hong537802d2018-08-15 13:15:42 -070056 auto boot_control = std::make_unique<BootControlAndroid>();
David Zeuthen753fadc2015-09-15 16:34:09 -040057 if (!boot_control->Init()) {
58 return nullptr;
59 }
Alex Vakulenkoce8c8ee2016-04-08 08:59:26 -070060 return std::move(boot_control);
Alex Deymob17327c2015-09-04 10:29:00 -070061}
62
63} // namespace boot_control
64
David Zeuthen753fadc2015-09-15 16:34:09 -040065bool BootControlAndroid::Init() {
Chris Phoenixafde8e82017-01-17 23:14:58 -080066 module_ = IBootControl::getService();
Connor O'Briencee6ad92016-11-21 13:53:52 -080067 if (module_ == nullptr) {
Steven Moreland927e00d2017-01-04 12:58:40 -080068 LOG(ERROR) << "Error getting bootctrl HIDL module.";
David Zeuthen753fadc2015-09-15 16:34:09 -040069 return false;
70 }
71
Steven Moreland927e00d2017-01-04 12:58:40 -080072 LOG(INFO) << "Loaded boot control hidl hal.";
David Zeuthen753fadc2015-09-15 16:34:09 -040073
Yifan Hong537802d2018-08-15 13:15:42 -070074 dynamic_control_ = std::make_unique<DynamicPartitionControlAndroid>();
75
David Zeuthen753fadc2015-09-15 16:34:09 -040076 return true;
77}
Alex Deymob17327c2015-09-04 10:29:00 -070078
Yifan Hong537802d2018-08-15 13:15:42 -070079void BootControlAndroid::Cleanup() {
80 dynamic_control_->Cleanup();
81}
82
Alex Deymob17327c2015-09-04 10:29:00 -070083unsigned int BootControlAndroid::GetNumSlots() const {
Connor O'Briencee6ad92016-11-21 13:53:52 -080084 return module_->getNumberSlots();
Alex Deymob17327c2015-09-04 10:29:00 -070085}
86
87BootControlInterface::Slot BootControlAndroid::GetCurrentSlot() const {
Connor O'Briencee6ad92016-11-21 13:53:52 -080088 return module_->getCurrentSlot();
Alex Deymob17327c2015-09-04 10:29:00 -070089}
90
Yifan Hong537802d2018-08-15 13:15:42 -070091bool BootControlAndroid::GetSuffix(Slot slot, string* suffix) const {
Connor O'Briencee6ad92016-11-21 13:53:52 -080092 auto store_suffix_cb = [&suffix](hidl_string cb_suffix) {
Yifan Hong537802d2018-08-15 13:15:42 -070093 *suffix = cb_suffix.c_str();
Connor O'Briencee6ad92016-11-21 13:53:52 -080094 };
95 Return<void> ret = module_->getSuffix(slot, store_suffix_cb);
96
Yifan Hong7b514b42016-12-21 13:02:00 -080097 if (!ret.isOk()) {
Alex Deymo31d95ac2015-09-17 11:56:18 -070098 LOG(ERROR) << "boot_control impl returned no suffix for slot "
99 << SlotName(slot);
David Zeuthen753fadc2015-09-15 16:34:09 -0400100 return false;
101 }
Yifan Hong537802d2018-08-15 13:15:42 -0700102 return true;
103}
104
Yifan Hong124a4602018-11-14 13:17:01 -0800105bool BootControlAndroid::IsSuperBlockDevice(
106 const base::FilePath& device_dir,
107 Slot slot,
108 const string& partition_name_suffix) const {
109 string source_device =
Yifan Hong700d7c12019-07-23 20:49:16 -0700110 device_dir.Append(dynamic_control_->GetSuperPartitionName(slot)).value();
Yifan Hong012508e2019-07-22 18:30:40 -0700111 auto source_metadata =
112 dynamic_control_->LoadMetadataBuilder(source_device, slot);
Yifan Hong124a4602018-11-14 13:17:01 -0800113 return source_metadata->HasBlockDevice(partition_name_suffix);
114}
Yifan Hongae04e192018-10-29 11:00:28 -0700115
Yifan Hong124a4602018-11-14 13:17:01 -0800116BootControlAndroid::DynamicPartitionDeviceStatus
117BootControlAndroid::GetDynamicPartitionDevice(
118 const base::FilePath& device_dir,
Yifan Hongae04e192018-10-29 11:00:28 -0700119 const string& partition_name_suffix,
120 Slot slot,
Yifan Hong124a4602018-11-14 13:17:01 -0800121 string* device) const {
Yifan Hong124a4602018-11-14 13:17:01 -0800122 string super_device =
Yifan Hong700d7c12019-07-23 20:49:16 -0700123 device_dir.Append(dynamic_control_->GetSuperPartitionName(slot)).value();
Yifan Hong124a4602018-11-14 13:17:01 -0800124
Yifan Hong012508e2019-07-22 18:30:40 -0700125 auto builder = dynamic_control_->LoadMetadataBuilder(super_device, slot);
Yifan Hongae04e192018-10-29 11:00:28 -0700126
127 if (builder == nullptr) {
Yifan Hongae04e192018-10-29 11:00:28 -0700128 LOG(ERROR) << "No metadata in slot "
129 << BootControlInterface::SlotName(slot);
130 return DynamicPartitionDeviceStatus::ERROR;
131 }
132
Yifan Hong8546a712019-03-28 14:42:53 -0700133 Slot current_slot = GetCurrentSlot();
Yifan Hongae04e192018-10-29 11:00:28 -0700134 if (builder->FindPartition(partition_name_suffix) == nullptr) {
135 LOG(INFO) << partition_name_suffix
136 << " is not in super partition metadata.";
Yifan Hong124a4602018-11-14 13:17:01 -0800137
Yifan Hong124a4602018-11-14 13:17:01 -0800138 if (IsSuperBlockDevice(device_dir, current_slot, partition_name_suffix)) {
139 LOG(ERROR) << "The static partition " << partition_name_suffix
140 << " is a block device for current metadata ("
Yifan Hong700d7c12019-07-23 20:49:16 -0700141 << dynamic_control_->GetSuperPartitionName(current_slot)
142 << ", slot " << BootControlInterface::SlotName(current_slot)
Yifan Hong124a4602018-11-14 13:17:01 -0800143 << "). It cannot be used as a logical partition.";
144 return DynamicPartitionDeviceStatus::ERROR;
145 }
146
Yifan Hongae04e192018-10-29 11:00:28 -0700147 return DynamicPartitionDeviceStatus::TRY_STATIC;
148 }
149
Yifan Hong8546a712019-03-28 14:42:53 -0700150 if (slot == current_slot) {
151 if (dynamic_control_->GetState(partition_name_suffix) !=
152 DmDeviceState::ACTIVE) {
153 LOG(WARNING) << partition_name_suffix << " is at current slot but it is "
154 << "not mapped. Now try to map it.";
155 } else {
156 if (dynamic_control_->GetDmDevicePathByName(partition_name_suffix,
157 device)) {
158 LOG(INFO) << partition_name_suffix
159 << " is mapped on device mapper: " << *device;
160 return DynamicPartitionDeviceStatus::SUCCESS;
161 }
162 LOG(ERROR) << partition_name_suffix << "is mapped but path is unknown.";
163 return DynamicPartitionDeviceStatus::ERROR;
Yifan Hongae04e192018-10-29 11:00:28 -0700164 }
Yifan Hongae04e192018-10-29 11:00:28 -0700165 }
166
Yifan Hong8546a712019-03-28 14:42:53 -0700167 bool force_writable = slot != current_slot;
168 if (dynamic_control_->MapPartitionOnDeviceMapper(
169 super_device, partition_name_suffix, slot, force_writable, device)) {
170 return DynamicPartitionDeviceStatus::SUCCESS;
Yifan Hongae04e192018-10-29 11:00:28 -0700171 }
Yifan Hongae04e192018-10-29 11:00:28 -0700172 return DynamicPartitionDeviceStatus::ERROR;
173}
Yifan Hongae04e192018-10-29 11:00:28 -0700174
Yifan Hong537802d2018-08-15 13:15:42 -0700175bool BootControlAndroid::GetPartitionDevice(const string& partition_name,
176 Slot slot,
177 string* device) const {
178 string suffix;
179 if (!GetSuffix(slot, &suffix)) {
180 return false;
181 }
Yifan Hongae04e192018-10-29 11:00:28 -0700182 const string partition_name_suffix = partition_name + suffix;
Yifan Hong537802d2018-08-15 13:15:42 -0700183
184 string device_dir_str;
185 if (!dynamic_control_->GetDeviceDir(&device_dir_str)) {
186 return false;
187 }
Yifan Hongae04e192018-10-29 11:00:28 -0700188 base::FilePath device_dir(device_dir_str);
David Zeuthen753fadc2015-09-15 16:34:09 -0400189
Yifan Hong1d9077f2018-12-07 12:09:37 -0800190 // When looking up target partition devices, treat them as static if the
191 // current payload doesn't encode them as dynamic partitions. This may happen
192 // when applying a retrofit update on top of a dynamic-partitions-enabled
193 // build.
Yifan Hong186bb682019-07-23 14:04:39 -0700194 if (dynamic_control_->GetDynamicPartitionsFeatureFlag().IsEnabled() &&
Yifan Hong1d9077f2018-12-07 12:09:37 -0800195 (slot == GetCurrentSlot() || is_target_dynamic_)) {
196 switch (GetDynamicPartitionDevice(
197 device_dir, partition_name_suffix, slot, device)) {
198 case DynamicPartitionDeviceStatus::SUCCESS:
199 return true;
200 case DynamicPartitionDeviceStatus::TRY_STATIC:
201 break;
202 case DynamicPartitionDeviceStatus::ERROR: // fallthrough
203 default:
204 return false;
205 }
Yifan Hongae04e192018-10-29 11:00:28 -0700206 }
207
208 base::FilePath path = device_dir.Append(partition_name_suffix);
Yifan Hong537802d2018-08-15 13:15:42 -0700209 if (!dynamic_control_->DeviceExists(path.value())) {
David Zeuthen753fadc2015-09-15 16:34:09 -0400210 LOG(ERROR) << "Device file " << path.value() << " does not exist.";
211 return false;
212 }
213
214 *device = path.value();
215 return true;
Alex Deymob17327c2015-09-04 10:29:00 -0700216}
217
218bool BootControlAndroid::IsSlotBootable(Slot slot) const {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800219 Return<BoolResult> ret = module_->isSlotBootable(slot);
Yifan Hong7b514b42016-12-21 13:02:00 -0800220 if (!ret.isOk()) {
Alex Deymo31d95ac2015-09-17 11:56:18 -0700221 LOG(ERROR) << "Unable to determine if slot " << SlotName(slot)
Amin Hassani7cc8bb02019-01-14 16:29:47 -0800222 << " is bootable: " << ret.description();
David Zeuthen753fadc2015-09-15 16:34:09 -0400223 return false;
224 }
Connor O'Briencee6ad92016-11-21 13:53:52 -0800225 if (ret == BoolResult::INVALID_SLOT) {
226 LOG(ERROR) << "Invalid slot: " << SlotName(slot);
227 return false;
228 }
229 return ret == BoolResult::TRUE;
Alex Deymob17327c2015-09-04 10:29:00 -0700230}
231
232bool BootControlAndroid::MarkSlotUnbootable(Slot slot) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800233 CommandResult result;
234 auto ret = module_->setSlotAsUnbootable(slot, StoreResultCallback(&result));
Yifan Hong7b514b42016-12-21 13:02:00 -0800235 if (!ret.isOk()) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800236 LOG(ERROR) << "Unable to call MarkSlotUnbootable for slot "
Amin Hassani7cc8bb02019-01-14 16:29:47 -0800237 << SlotName(slot) << ": " << ret.description();
David Zeuthen753fadc2015-09-15 16:34:09 -0400238 return false;
239 }
Connor O'Briencee6ad92016-11-21 13:53:52 -0800240 if (!result.success) {
241 LOG(ERROR) << "Unable to mark slot " << SlotName(slot)
242 << " as unbootable: " << result.errMsg.c_str();
243 }
244 return result.success;
Alex Deymob17327c2015-09-04 10:29:00 -0700245}
246
Alex Deymo31d95ac2015-09-17 11:56:18 -0700247bool BootControlAndroid::SetActiveBootSlot(Slot slot) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800248 CommandResult result;
249 auto ret = module_->setActiveBootSlot(slot, StoreResultCallback(&result));
Yifan Hong7b514b42016-12-21 13:02:00 -0800250 if (!ret.isOk()) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800251 LOG(ERROR) << "Unable to call SetActiveBootSlot for slot " << SlotName(slot)
Yifan Hong7b514b42016-12-21 13:02:00 -0800252 << ": " << ret.description();
Connor O'Briencee6ad92016-11-21 13:53:52 -0800253 return false;
Alex Deymo29dcbf32016-10-06 13:33:20 -0700254 }
Connor O'Briencee6ad92016-11-21 13:53:52 -0800255 if (!result.success) {
256 LOG(ERROR) << "Unable to set the active slot to slot " << SlotName(slot)
257 << ": " << result.errMsg.c_str();
258 }
259 return result.success;
Alex Deymo31d95ac2015-09-17 11:56:18 -0700260}
261
Alex Deymoaa26f622015-09-16 18:21:27 -0700262bool BootControlAndroid::MarkBootSuccessfulAsync(
263 base::Callback<void(bool)> callback) {
Connor O'Briencee6ad92016-11-21 13:53:52 -0800264 CommandResult result;
265 auto ret = module_->markBootSuccessful(StoreResultCallback(&result));
Yifan Hong7b514b42016-12-21 13:02:00 -0800266 if (!ret.isOk()) {
Amin Hassani7cc8bb02019-01-14 16:29:47 -0800267 LOG(ERROR) << "Unable to call MarkBootSuccessful: " << ret.description();
Connor O'Briencee6ad92016-11-21 13:53:52 -0800268 return false;
269 }
270 if (!result.success) {
271 LOG(ERROR) << "Unable to mark boot successful: " << result.errMsg.c_str();
Alex Deymoaa26f622015-09-16 18:21:27 -0700272 }
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700273 return brillo::MessageLoop::current()->PostTask(
Connor O'Briencee6ad92016-11-21 13:53:52 -0800274 FROM_HERE, base::Bind(callback, result.success)) !=
Alex Vakulenko3f39d5c2015-10-13 09:27:13 -0700275 brillo::MessageLoop::kTaskIdNull;
Alex Deymoaa26f622015-09-16 18:21:27 -0700276}
277
Yifan Hong13d41cb2019-09-16 13:18:22 -0700278bool BootControlAndroid::PreparePartitionsForUpdate(
Tao Bao3406c772019-01-02 15:34:35 -0800279 Slot target_slot,
Yifan Hong13d41cb2019-09-16 13:18:22 -0700280 const DeltaArchiveManifest& manifest,
Tao Bao3406c772019-01-02 15:34:35 -0800281 bool update_metadata) {
Mark Salyzyn62b42c82018-12-05 13:33:17 -0800282 if (fs_mgr_overlayfs_is_setup()) {
283 // Non DAP devices can use overlayfs as well.
284 LOG(WARNING)
285 << "overlayfs overrides are active and can interfere with our "
286 "resources.\n"
287 << "run adb enable-verity to deactivate if required and try again.";
288 }
Yifan Hong186bb682019-07-23 14:04:39 -0700289 if (!dynamic_control_->GetDynamicPartitionsFeatureFlag().IsEnabled()) {
Yifan Hong537802d2018-08-15 13:15:42 -0700290 return true;
291 }
292
Yifan Hong1d9077f2018-12-07 12:09:37 -0800293 auto source_slot = GetCurrentSlot();
294 if (target_slot == source_slot) {
Yifan Hong13d41cb2019-09-16 13:18:22 -0700295 LOG(ERROR) << "Cannot call PreparePartitionsForUpdate on current slot.";
Yifan Hong537802d2018-08-15 13:15:42 -0700296 return false;
297 }
298
Yifan Hong1d9077f2018-12-07 12:09:37 -0800299 // Although the current build supports dynamic partitions, the given payload
300 // doesn't use it for target partitions. This could happen when applying a
301 // retrofit update. Skip updating the partition metadata for the target slot.
Yifan Hong13d41cb2019-09-16 13:18:22 -0700302 is_target_dynamic_ = !manifest.dynamic_partition_metadata().groups().empty();
Yifan Hong1d9077f2018-12-07 12:09:37 -0800303 if (!is_target_dynamic_) {
304 return true;
305 }
306
Tao Bao3406c772019-01-02 15:34:35 -0800307 if (!update_metadata) {
308 return true;
309 }
310
Yifan Hong012508e2019-07-22 18:30:40 -0700311 return dynamic_control_->PreparePartitionsForUpdate(
Yifan Hong13d41cb2019-09-16 13:18:22 -0700312 source_slot, target_slot, manifest);
Yifan Hong537802d2018-08-15 13:15:42 -0700313}
314
Alex Deymob17327c2015-09-04 10:29:00 -0700315} // namespace chromeos_update_engine