1cee6ad93d1772be82477fe30407c768160406539Connor O'Brien//
2cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// Copyright (C) 2015 The Android Open Source Project
3cee6ad93d1772be82477fe30407c768160406539Connor O'Brien//
4cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// Licensed under the Apache License, Version 2.0 (the "License");
5cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// you may not use this file except in compliance with the License.
6cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// You may obtain a copy of the License at
7cee6ad93d1772be82477fe30407c768160406539Connor O'Brien//
8cee6ad93d1772be82477fe30407c768160406539Connor O'Brien//      http://www.apache.org/licenses/LICENSE-2.0
9cee6ad93d1772be82477fe30407c768160406539Connor O'Brien//
10cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// Unless required by applicable law or agreed to in writing, software
11cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// distributed under the License is distributed on an "AS IS" BASIS,
12cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// See the License for the specific language governing permissions and
14cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// limitations under the License.
15cee6ad93d1772be82477fe30407c768160406539Connor O'Brien//
16cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
17cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#include "update_engine/boot_control_recovery.h"
18cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
19cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#include <base/bind.h>
20cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#include <base/files/file_util.h>
21cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#include <base/logging.h>
22cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#include <base/strings/string_util.h>
23cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#include <brillo/message_loops/message_loop.h>
24cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
25cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#include "update_engine/common/utils.h"
26cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#include "update_engine/utils_android.h"
27cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
28cee6ad93d1772be82477fe30407c768160406539Connor O'Brienusing std::string;
29cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
30cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#ifndef _UE_SIDELOAD
31cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#error "BootControlRecovery should only be used for update_engine_sideload."
32cee6ad93d1772be82477fe30407c768160406539Connor O'Brien#endif
33cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
34cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// When called from update_engine_sideload, we don't attempt to dynamically load
35cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// the right boot_control HAL, instead we use the only HAL statically linked in
36cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// via the PRODUCT_STATIC_BOOT_CONTROL_HAL make variable and access the module
37cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// struct directly.
38cee6ad93d1772be82477fe30407c768160406539Connor O'Brienextern const hw_module_t HAL_MODULE_INFO_SYM;
39cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
40cee6ad93d1772be82477fe30407c768160406539Connor O'Briennamespace chromeos_update_engine {
41cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
42cee6ad93d1772be82477fe30407c768160406539Connor O'Briennamespace boot_control {
43cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
44cee6ad93d1772be82477fe30407c768160406539Connor O'Brien// Factory defined in boot_control.h.
45cee6ad93d1772be82477fe30407c768160406539Connor O'Brienstd::unique_ptr<BootControlInterface> CreateBootControl() {
46cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  std::unique_ptr<BootControlRecovery> boot_control(new BootControlRecovery());
47cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (!boot_control->Init()) {
48cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    return nullptr;
49cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  }
50cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  return std::move(boot_control);
51cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}
52cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
53cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}  // namespace boot_control
54cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
55cee6ad93d1772be82477fe30407c768160406539Connor O'Brienbool BootControlRecovery::Init() {
56cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  const hw_module_t* hw_module;
57cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  int ret;
58cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
59cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // For update_engine_sideload, we simulate the hw_get_module() by accessing it
60cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // from the current process directly.
61cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  hw_module = &HAL_MODULE_INFO_SYM;
62cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  ret = 0;
63cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (!hw_module ||
64cee6ad93d1772be82477fe30407c768160406539Connor O'Brien      strcmp(BOOT_CONTROL_HARDWARE_MODULE_ID, hw_module->id) != 0) {
65cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    ret = -EINVAL;
66cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  }
67cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (ret != 0) {
68cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    LOG(ERROR) << "Error loading boot_control HAL implementation.";
69cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    return false;
70cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  }
71cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
72cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  module_ = reinterpret_cast<boot_control_module_t*>(
73cee6ad93d1772be82477fe30407c768160406539Connor O'Brien      const_cast<hw_module_t*>(hw_module));
74cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  module_->init(module_);
75cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
76cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  LOG(INFO) << "Loaded boot_control HAL "
77cee6ad93d1772be82477fe30407c768160406539Connor O'Brien            << "'" << hw_module->name << "' "
78cee6ad93d1772be82477fe30407c768160406539Connor O'Brien            << "version " << (hw_module->module_api_version >> 8) << "."
79cee6ad93d1772be82477fe30407c768160406539Connor O'Brien            << (hw_module->module_api_version & 0xff) << " "
80cee6ad93d1772be82477fe30407c768160406539Connor O'Brien            << "authored by '" << hw_module->author << "'.";
81cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  return true;
82cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}
83cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
84cee6ad93d1772be82477fe30407c768160406539Connor O'Brienunsigned int BootControlRecovery::GetNumSlots() const {
85cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  return module_->getNumberSlots(module_);
86cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}
87cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
88cee6ad93d1772be82477fe30407c768160406539Connor O'BrienBootControlInterface::Slot BootControlRecovery::GetCurrentSlot() const {
89cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  return module_->getCurrentSlot(module_);
90cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}
91cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
92cee6ad93d1772be82477fe30407c768160406539Connor O'Brienbool BootControlRecovery::GetPartitionDevice(const string& partition_name,
93cee6ad93d1772be82477fe30407c768160406539Connor O'Brien                                             Slot slot,
94cee6ad93d1772be82477fe30407c768160406539Connor O'Brien                                             string* device) const {
95cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // We can't use fs_mgr to look up |partition_name| because fstab
96cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // doesn't list every slot partition (it uses the slotselect option
97cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // to mask the suffix).
98cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  //
99cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // We can however assume that there's an entry for the /misc mount
100cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // point and use that to get the device file for the misc
101cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // partition. This helps us locate the disk that |partition_name|
102cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // resides on. From there we'll assume that a by-name scheme is used
103cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // so we can just replace the trailing "misc" by the given
104cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // |partition_name| and suffix corresponding to |slot|, e.g.
105cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  //
106cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  //   /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
107cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  //   /dev/block/platform/soc.0/7824900.sdhci/by-name/boot_a
108cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  //
109cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // If needed, it's possible to relax the by-name assumption in the
110cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // future by trawling /sys/block looking for the appropriate sibling
111cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // of misc and then finding an entry in /dev matching the sysfs
112cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  // entry.
113cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
114cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  base::FilePath misc_device;
115cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (!utils::DeviceForMountPoint("/misc", &misc_device))
116cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    return false;
117cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
118cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (!utils::IsSymlink(misc_device.value().c_str())) {
119cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    LOG(ERROR) << "Device file " << misc_device.value() << " for /misc "
120cee6ad93d1772be82477fe30407c768160406539Connor O'Brien               << "is not a symlink.";
121cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    return false;
122cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  }
123cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
124cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  const char* suffix = module_->getSuffix(module_, slot);
125cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (suffix == nullptr) {
126cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    LOG(ERROR) << "boot_control impl returned no suffix for slot "
127cee6ad93d1772be82477fe30407c768160406539Connor O'Brien               << SlotName(slot);
128cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    return false;
129cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  }
130cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
131cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  base::FilePath path = misc_device.DirName().Append(partition_name + suffix);
132cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (!base::PathExists(path)) {
133cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    LOG(ERROR) << "Device file " << path.value() << " does not exist.";
134cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    return false;
135cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  }
136cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
137cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  *device = path.value();
138cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  return true;
139cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}
140cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
141cee6ad93d1772be82477fe30407c768160406539Connor O'Brienbool BootControlRecovery::IsSlotBootable(Slot slot) const {
142cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  int ret = module_->isSlotBootable(module_, slot);
143cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (ret < 0) {
144cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    LOG(ERROR) << "Unable to determine if slot " << SlotName(slot)
145cee6ad93d1772be82477fe30407c768160406539Connor O'Brien               << " is bootable: " << strerror(-ret);
146cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    return false;
147cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  }
148cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  return ret == 1;
149cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}
150cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
151cee6ad93d1772be82477fe30407c768160406539Connor O'Brienbool BootControlRecovery::MarkSlotUnbootable(Slot slot) {
152cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  int ret = module_->setSlotAsUnbootable(module_, slot);
153cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (ret < 0) {
154cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    LOG(ERROR) << "Unable to mark slot " << SlotName(slot)
155cee6ad93d1772be82477fe30407c768160406539Connor O'Brien               << " as bootable: " << strerror(-ret);
156cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    return false;
157cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  }
158cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  return ret == 0;
159cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}
160cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
161cee6ad93d1772be82477fe30407c768160406539Connor O'Brienbool BootControlRecovery::SetActiveBootSlot(Slot slot) {
162cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  int ret = module_->setActiveBootSlot(module_, slot);
163cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (ret < 0) {
164cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    LOG(ERROR) << "Unable to set the active slot to slot " << SlotName(slot)
165cee6ad93d1772be82477fe30407c768160406539Connor O'Brien               << ": " << strerror(-ret);
166cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  }
167cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  return ret == 0;
168cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}
169cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
170cee6ad93d1772be82477fe30407c768160406539Connor O'Brienbool BootControlRecovery::MarkBootSuccessfulAsync(
171cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    base::Callback<void(bool)> callback) {
172cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  int ret = module_->markBootSuccessful(module_);
173cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  if (ret < 0) {
174cee6ad93d1772be82477fe30407c768160406539Connor O'Brien    LOG(ERROR) << "Unable to mark boot successful: " << strerror(-ret);
175cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  }
176cee6ad93d1772be82477fe30407c768160406539Connor O'Brien  return brillo::MessageLoop::current()->PostTask(
177cee6ad93d1772be82477fe30407c768160406539Connor O'Brien             FROM_HERE, base::Bind(callback, ret == 0)) !=
178cee6ad93d1772be82477fe30407c768160406539Connor O'Brien         brillo::MessageLoop::kTaskIdNull;
179cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}
180cee6ad93d1772be82477fe30407c768160406539Connor O'Brien
181cee6ad93d1772be82477fe30407c768160406539Connor O'Brien}  // namespace chromeos_update_engine
182