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