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