1b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo//
2b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// Copyright (C) 2015 The Android Open Source Project
3b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo//
4b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// Licensed under the Apache License, Version 2.0 (the "License");
5b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// you may not use this file except in compliance with the License.
6b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// You may obtain a copy of the License at
7b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo//
8b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo//      http://www.apache.org/licenses/LICENSE-2.0
9b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo//
10b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// Unless required by applicable law or agreed to in writing, software
11b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// distributed under the License is distributed on an "AS IS" BASIS,
12b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// See the License for the specific language governing permissions and
14b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// limitations under the License.
15b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo//
16b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
171b03f9f983a22fabb8d53e036abf1b192e7d5811Alex Deymo#include "update_engine/boot_control_android.h"
18b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
19aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo#include <base/bind.h>
20753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen#include <base/files/file_util.h>
21aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo#include <base/logging.h>
22753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen#include <base/strings/string_util.h>
233f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko#include <brillo/make_unique_ptr.h>
243f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko#include <brillo/message_loops/message_loop.h>
25b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
2639910dcd1d68987ccee7c3031dc269233a8490bbAlex Deymo#include "update_engine/common/utils.h"
27a918f9daede277d043e5b3b8443d712c88c949daAlex Deymo#include "update_engine/utils_android.h"
28b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
29b17327ce55e7132da1f64039040df93a8c260fefAlex Deymousing std::string;
30b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
31d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo#ifdef _UE_SIDELOAD
32d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo// When called from update_engine_sideload, we don't attempt to dynamically load
33d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo// the right boot_control HAL, instead we use the only HAL statically linked in
34d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo// via the PRODUCT_STATIC_BOOT_CONTROL_HAL make variable and access the module
35d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo// struct directly.
36d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymoextern const hw_module_t HAL_MODULE_INFO_SYM;
37d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo#endif  // _UE_SIDELOAD
38d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo
39b17327ce55e7132da1f64039040df93a8c260fefAlex Deymonamespace chromeos_update_engine {
40b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
41b17327ce55e7132da1f64039040df93a8c260fefAlex Deymonamespace boot_control {
42b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
43b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo// Factory defined in boot_control.h.
44b17327ce55e7132da1f64039040df93a8c260fefAlex Deymostd::unique_ptr<BootControlInterface> CreateBootControl() {
45753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  std::unique_ptr<BootControlAndroid> boot_control(new BootControlAndroid());
46753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  if (!boot_control->Init()) {
47753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    return nullptr;
48753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  }
493f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  return brillo::make_unique_ptr(boot_control.release());
50b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo}
51b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
52b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo}  // namespace boot_control
53b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
54753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthenbool BootControlAndroid::Init() {
55753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  const hw_module_t* hw_module;
56753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  int ret;
57753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen
58d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo#ifdef _UE_SIDELOAD
59d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo  // For update_engine_sideload, we simulate the hw_get_module() by accessing it
60d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo  // from the current process directly.
61d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo  hw_module = &HAL_MODULE_INFO_SYM;
62d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo  ret = 0;
63d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo  if (!hw_module ||
64d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo      strcmp(BOOT_CONTROL_HARDWARE_MODULE_ID, hw_module->id) != 0) {
65d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo    ret = -EINVAL;
66d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo  }
67d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo#else  // !_UE_SIDELOAD
68753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  ret = hw_get_module(BOOT_CONTROL_HARDWARE_MODULE_ID, &hw_module);
69d18829480c833dd9416a3778900cb4ddaad375b2Alex Deymo#endif  // _UE_SIDELOAD
70753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  if (ret != 0) {
71753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    LOG(ERROR) << "Error loading boot_control HAL implementation.";
72753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    return false;
73753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  }
74753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen
75753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  module_ = reinterpret_cast<boot_control_module_t*>(const_cast<hw_module_t*>(hw_module));
76753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  module_->init(module_);
77753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen
78753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  LOG(INFO) << "Loaded boot_control HAL "
79753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen            << "'" << hw_module->name << "' "
80753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen            << "version " << (hw_module->module_api_version>>8) << "."
81753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen            << (hw_module->module_api_version&0xff) << " "
82753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen            << "authored by '" << hw_module->author << "'.";
83753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  return true;
84753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen}
85b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
86b17327ce55e7132da1f64039040df93a8c260fefAlex Deymounsigned int BootControlAndroid::GetNumSlots() const {
87753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  return module_->getNumberSlots(module_);
88b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo}
89b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
90b17327ce55e7132da1f64039040df93a8c260fefAlex DeymoBootControlInterface::Slot BootControlAndroid::GetCurrentSlot() const {
91753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  return module_->getCurrentSlot(module_);
92b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo}
93b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
94b17327ce55e7132da1f64039040df93a8c260fefAlex Deymobool BootControlAndroid::GetPartitionDevice(const string& partition_name,
95753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen                                            Slot slot,
96b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo                                            string* device) const {
97753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // We can't use fs_mgr to look up |partition_name| because fstab
98753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // doesn't list every slot partition (it uses the slotselect option
99753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // to mask the suffix).
100753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  //
101753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // We can however assume that there's an entry for the /misc mount
102753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // point and use that to get the device file for the misc
103753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // partition. This helps us locate the disk that |partition_name|
104753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // resides on. From there we'll assume that a by-name scheme is used
105753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // so we can just replace the trailing "misc" by the given
106753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // |partition_name| and suffix corresponding to |slot|, e.g.
107753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  //
108753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  //   /dev/block/platform/soc.0/7824900.sdhci/by-name/misc ->
109753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  //   /dev/block/platform/soc.0/7824900.sdhci/by-name/boot_a
110753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  //
111753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // If needed, it's possible to relax the by-name assumption in the
112753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // future by trawling /sys/block looking for the appropriate sibling
113753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // of misc and then finding an entry in /dev matching the sysfs
114753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  // entry.
115753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen
116a918f9daede277d043e5b3b8443d712c88c949daAlex Deymo  base::FilePath misc_device;
117a918f9daede277d043e5b3b8443d712c88c949daAlex Deymo  if (!utils::DeviceForMountPoint("/misc", &misc_device))
118753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    return false;
119753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen
12012542ace0f43c5afaf1e7112556b71aea8454c79Alex Deymo  if (!utils::IsSymlink(misc_device.value().c_str())) {
121753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    LOG(ERROR) << "Device file " << misc_device.value() << " for /misc "
12212542ace0f43c5afaf1e7112556b71aea8454c79Alex Deymo               << "is not a symlink.";
123753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    return false;
124753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  }
125753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen
126753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  const char* suffix = module_->getSuffix(module_, slot);
127753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  if (suffix == nullptr) {
12831d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo    LOG(ERROR) << "boot_control impl returned no suffix for slot "
12931d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo               << SlotName(slot);
130753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    return false;
131753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  }
132753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen
133753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  base::FilePath path = misc_device.DirName().Append(partition_name + suffix);
134753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  if (!base::PathExists(path)) {
135753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    LOG(ERROR) << "Device file " << path.value() << " does not exist.";
136753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    return false;
137753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  }
138753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen
139753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  *device = path.value();
140753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  return true;
141b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo}
142b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
143b17327ce55e7132da1f64039040df93a8c260fefAlex Deymobool BootControlAndroid::IsSlotBootable(Slot slot) const {
144753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  int ret = module_->isSlotBootable(module_, slot);
145753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  if (ret < 0) {
14631d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo    LOG(ERROR) << "Unable to determine if slot " << SlotName(slot)
147753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen               << " is bootable: " << strerror(-ret);
148753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    return false;
149753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  }
150753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  return ret == 1;
151b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo}
152b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
153b17327ce55e7132da1f64039040df93a8c260fefAlex Deymobool BootControlAndroid::MarkSlotUnbootable(Slot slot) {
154753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  int ret = module_->setSlotAsUnbootable(module_, slot);
155753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  if (ret < 0) {
15631d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo    LOG(ERROR) << "Unable to mark slot " << SlotName(slot)
157753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen               << " as bootable: " << strerror(-ret);
158753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen    return false;
159753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  }
160753fadc8805f662e5af3a66f694207b04fbef8bbDavid Zeuthen  return ret == 0;
161b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo}
162b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo
16331d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymobool BootControlAndroid::SetActiveBootSlot(Slot slot) {
16431d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  int ret = module_->setActiveBootSlot(module_, slot);
16531d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  if (ret < 0) {
16631d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo    LOG(ERROR) << "Unable to set the active slot to slot " << SlotName(slot)
16731d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo               << ": " << strerror(-ret);
16831d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  }
16931d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo  return ret == 0;
17031d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo}
17131d95ac85d294b2b1bfa293835013e66c010fbcfAlex Deymo
172aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymobool BootControlAndroid::MarkBootSuccessfulAsync(
173aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo    base::Callback<void(bool)> callback) {
174aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo  int ret = module_->markBootSuccessful(module_);
175aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo  if (ret < 0) {
176aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo    LOG(ERROR) << "Unable to mark boot successful: " << strerror(-ret);
177aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo  }
1783f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko  return brillo::MessageLoop::current()->PostTask(
179aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo             FROM_HERE, base::Bind(callback, ret == 0)) !=
1803f39d5cc753905874d8d93bef94f857b8808f19eAlex Vakulenko         brillo::MessageLoop::kTaskIdNull;
181aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo}
182aa26f6240865d43f8cecc97bde7828f9b82bc17dAlex Deymo
183b17327ce55e7132da1f64039040df93a8c260fefAlex Deymo}  // namespace chromeos_update_engine
184