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 <memory> 20 #include <utility> 21 #include <vector> 22 23 #include <base/bind.h> 24 #include <base/logging.h> 25 #include <bootloader_message/bootloader_message.h> 26 #include <brillo/message_loops/message_loop.h> 27 28 #include "update_engine/common/utils.h" 29 #include "update_engine/dynamic_partition_control_android.h" 30 31 using std::string; 32 33 using android::dm::DmDeviceState; 34 using android::hardware::hidl_string; 35 using android::hardware::Return; 36 using android::hardware::boot::V1_0::BoolResult; 37 using android::hardware::boot::V1_0::CommandResult; 38 using android::hardware::boot::V1_0::IBootControl; 39 using Slot = chromeos_update_engine::BootControlInterface::Slot; 40 41 namespace { 42 43 auto StoreResultCallback(CommandResult* dest) { 44 return [dest](const CommandResult& result) { *dest = result; }; 45 } 46 } // namespace 47 48 namespace chromeos_update_engine { 49 50 namespace boot_control { 51 52 // Factory defined in boot_control.h. 53 std::unique_ptr<BootControlInterface> CreateBootControl() { 54 auto boot_control = std::make_unique<BootControlAndroid>(); 55 if (!boot_control->Init()) { 56 return nullptr; 57 } 58 return std::move(boot_control); 59 } 60 61 } // namespace boot_control 62 63 bool BootControlAndroid::Init() { 64 module_ = IBootControl::getService(); 65 if (module_ == nullptr) { 66 LOG(ERROR) << "Error getting bootctrl HIDL module."; 67 return false; 68 } 69 70 LOG(INFO) << "Loaded boot control hidl hal."; 71 72 dynamic_control_ = std::make_unique<DynamicPartitionControlAndroid>(); 73 74 return true; 75 } 76 77 unsigned int BootControlAndroid::GetNumSlots() const { 78 return module_->getNumberSlots(); 79 } 80 81 BootControlInterface::Slot BootControlAndroid::GetCurrentSlot() const { 82 return module_->getCurrentSlot(); 83 } 84 85 86 bool BootControlAndroid::GetPartitionDevice(const string& partition_name, 87 Slot slot, 88 string* device) const { 89 return dynamic_control_->GetPartitionDevice( 90 partition_name, slot, GetCurrentSlot(), device); 91 } 92 93 bool BootControlAndroid::IsSlotBootable(Slot slot) const { 94 Return<BoolResult> ret = module_->isSlotBootable(slot); 95 if (!ret.isOk()) { 96 LOG(ERROR) << "Unable to determine if slot " << SlotName(slot) 97 << " is bootable: " << ret.description(); 98 return false; 99 } 100 if (ret == BoolResult::INVALID_SLOT) { 101 LOG(ERROR) << "Invalid slot: " << SlotName(slot); 102 return false; 103 } 104 return ret == BoolResult::TRUE; 105 } 106 107 bool BootControlAndroid::MarkSlotUnbootable(Slot slot) { 108 CommandResult result; 109 auto ret = module_->setSlotAsUnbootable(slot, StoreResultCallback(&result)); 110 if (!ret.isOk()) { 111 LOG(ERROR) << "Unable to call MarkSlotUnbootable for slot " 112 << SlotName(slot) << ": " << ret.description(); 113 return false; 114 } 115 if (!result.success) { 116 LOG(ERROR) << "Unable to mark slot " << SlotName(slot) 117 << " as unbootable: " << result.errMsg.c_str(); 118 } 119 return result.success; 120 } 121 122 bool BootControlAndroid::SetActiveBootSlot(Slot slot) { 123 CommandResult result; 124 auto ret = module_->setActiveBootSlot(slot, StoreResultCallback(&result)); 125 if (!ret.isOk()) { 126 LOG(ERROR) << "Unable to call SetActiveBootSlot for slot " << SlotName(slot) 127 << ": " << ret.description(); 128 return false; 129 } 130 if (!result.success) { 131 LOG(ERROR) << "Unable to set the active slot to slot " << SlotName(slot) 132 << ": " << result.errMsg.c_str(); 133 } 134 return result.success; 135 } 136 137 bool BootControlAndroid::MarkBootSuccessfulAsync( 138 base::Callback<void(bool)> callback) { 139 CommandResult result; 140 auto ret = module_->markBootSuccessful(StoreResultCallback(&result)); 141 if (!ret.isOk()) { 142 LOG(ERROR) << "Unable to call MarkBootSuccessful: " << ret.description(); 143 return false; 144 } 145 if (!result.success) { 146 LOG(ERROR) << "Unable to mark boot successful: " << result.errMsg.c_str(); 147 } 148 return brillo::MessageLoop::current()->PostTask( 149 FROM_HERE, base::Bind(callback, result.success)) != 150 brillo::MessageLoop::kTaskIdNull; 151 } 152 153 bool BootControlAndroid::IsSlotMarkedSuccessful( 154 BootControlInterface::Slot slot) const { 155 Return<BoolResult> ret = module_->isSlotMarkedSuccessful(slot); 156 CommandResult result; 157 if (!ret.isOk()) { 158 LOG(ERROR) << "Unable to determine if slot " << SlotName(slot) 159 << " is marked successful: " << ret.description(); 160 return false; 161 } 162 if (ret == BoolResult::INVALID_SLOT) { 163 LOG(ERROR) << "Invalid slot: " << SlotName(slot); 164 return false; 165 } 166 return ret == BoolResult::TRUE; 167 } 168 169 DynamicPartitionControlInterface* 170 BootControlAndroid::GetDynamicPartitionControl() { 171 return dynamic_control_.get(); 172 } 173 174 } // namespace chromeos_update_engine 175