source bootctrl changes
[GitHub/moto-9609/twrp_device_motorola_troika.git] / bootctrl / BootControl.cpp
CommitLineData
f8cbf40d 1/*\r
2 * Copyright (C) 2020 The LineageOS Project\r
3 *\r
4 * Licensed under the Apache License, Version 2.0 (the "License");\r
5 * you may not use this file except in compliance with the License.\r
6 * You may obtain a copy of the License at\r
7 *\r
8 * http://www.apache.org/licenses/LICENSE-2.0\r
9 *\r
10 * Unless required by applicable law or agreed to in writing, software\r
11 * distributed under the License is distributed on an "AS IS" BASIS,\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13 * See the License for the specific language governing permissions and\r
14 * limitations under the License.\r
15 */\r
16\r
17#include "BootControl.h"\r
18\r
19#include <fstream>\r
20\r
21namespace android {\r
22namespace hardware {\r
23namespace boot {\r
24namespace V1_0 {\r
25namespace implementation {\r
26\r
27bool BootControl::readMetadata(bctl_metadata_t& data) {\r
28 std::fstream in(mBlkDevice, std::ios::binary | std::ios::in);\r
29\r
30 if (in.fail()) {\r
31 return false;\r
32 }\r
33\r
34 in.seekg(BCTL_METADATA_OFFSET);\r
35\r
36 if (in.fail()) {\r
37 return false;\r
38 }\r
39\r
40 in.read(reinterpret_cast<char*>(&data), sizeof(bctl_metadata_t));\r
41\r
42 if (!validateMetadata(data))\r
89ba5902 43 return false;\r
f8cbf40d 44\r
45 return !in.eof() && !in.fail();\r
46}\r
47\r
48bool BootControl::writeMetadata(bctl_metadata_t& data) {\r
49 if (!validateMetadata(data))\r
89ba5902 50 return false;\r
f8cbf40d 51\r
52 // We use std::ios::in | std::ios::out even though we only write so that\r
53 // we don't truncate or append to the file, but rather overwrite the file\r
54 // in the exact place that we want to write the struct to.\r
55 std::fstream out(mBlkDevice, std::ios::binary | std::ios::in | std::ios::out);\r
56\r
57 if (out.fail()) {\r
58 return false;\r
59 }\r
60\r
61 out.seekp(BCTL_METADATA_OFFSET);\r
62\r
63 if (out.fail()) {\r
64 return false;\r
65 }\r
66\r
67 out.write(reinterpret_cast<const char*>(&data), sizeof(bctl_metadata_t));\r
68\r
69 return !out.eof() && !out.fail();\r
70}\r
71\r
72bool BootControl::validateMetadata(bctl_metadata_t& data) {\r
73 if (data.slot_info[0].magic != BCTL_METADATA_MAGIC || data.slot_info[1].magic != BCTL_METADATA_MAGIC) {\r
74 return false;\r
75 }\r
76 \r
77 return true;\r
78}\r
79\r
80void BootControl::resetMetadata(bctl_metadata_t& data) {\r
81 // reset to defaults\r
82 data.slot_info[0].magic = BCTL_METADATA_MAGIC;\r
83 data.slot_info[0].bootable = 1;\r
84 data.slot_info[0].is_active = 1;\r
85 data.slot_info[0].boot_successful = 0;\r
86 data.slot_info[0].tries_remaining = 7;\r
87\r
88 data.slot_info[1].magic = BCTL_METADATA_MAGIC;\r
89 data.slot_info[1].bootable = 1;\r
90 data.slot_info[1].is_active = 0;\r
91 data.slot_info[1].boot_successful = 0;\r
92 data.slot_info[1].tries_remaining = 7;\r
93}\r
94\r
95// Methods from ::android::hardware::boot::V1_0::IBootControl follow.\r
96Return<uint32_t> BootControl::getNumberSlots() {\r
97 return 2;\r
98}\r
99\r
100Return<uint32_t> BootControl::getCurrentSlot() {\r
101 bctl_metadata_t data;\r
102\r
103 if (readMetadata(data)) {\r
104 // This is a clever hack because if slot b is active,\r
105 // is_active will be 0 and if slot a is active, is_active\r
106 // will be 1. In other words, the "not" value of slot A's\r
107 // is_active var lines up to the current active slot index.\r
108 return !data.slot_info[0].is_active;\r
109 }\r
110\r
111 return 0;\r
112}\r
113\r
114Return<void> BootControl::markBootSuccessful(markBootSuccessful_cb _hidl_cb) {\r
115 bctl_metadata_t data;\r
116 bool success = false;\r
117 int active_slot;\r
118\r
119 if (readMetadata(data)) {\r
120 active_slot = !data.slot_info[0].is_active;\r
121 \r
89ba5902 122 data.slot_info[active_slot].boot_successful = 1;\r
f8cbf40d 123 data.slot_info[active_slot].tries_remaining = 0;\r
124\r
125 if (success)\r
126 if (writeMetadata(data)) {\r
127 _hidl_cb(CommandResult{true, ""});\r
128 } else {\r
129 _hidl_cb(CommandResult{false, "Failed to write metadata"});\r
130 }\r
131 else {\r
132 _hidl_cb(CommandResult{false, "No active slot"});\r
133 }\r
134 } else {\r
135 _hidl_cb(CommandResult{false, "Failed to read metadata"});\r
136 }\r
137\r
138 return Void();\r
139}\r
140\r
141Return<void> BootControl::setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) {\r
142 bctl_metadata_t data;\r
143 int slot2 = (slot == 0) ? 1 : 0;\r
144\r
145 if (slot < 2) {\r
146 if (readMetadata(data)) {\r
147 data.slot_info[slot].bootable = 1;\r
148 data.slot_info[slot].is_active = 1;\r
149 data.slot_info[slot].boot_successful = 0;\r
150 data.slot_info[slot].tries_remaining = 7;\r
151 \r
152 data.slot_info[slot2].bootable = 1;\r
153 data.slot_info[slot2].is_active = 0;\r
154 data.slot_info[slot2].boot_successful = 0;\r
155 data.slot_info[slot2].tries_remaining = 7;\r
156\r
157 if (writeMetadata(data)) {\r
158 _hidl_cb(CommandResult{true, ""});\r
159 } else {\r
160 _hidl_cb(CommandResult{false, "Failed to write metadata"});\r
161 }\r
162 } else {\r
163 _hidl_cb(CommandResult{false, "Failed to read metadata"});\r
164 }\r
165 } else {\r
166 _hidl_cb(CommandResult{false, "Invalid slot"});\r
167 }\r
168\r
169 return Void();\r
170}\r
171\r
172Return<void> BootControl::setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) {\r
173 bctl_metadata_t data;\r
174\r
175 if (slot < 2) {\r
176 if (readMetadata(data)) {\r
177 data.slot_info[slot].bootable = 0;\r
178\r
179 if (writeMetadata(data)) {\r
180 _hidl_cb(CommandResult{true, ""});\r
181 } else {\r
182 _hidl_cb(CommandResult{false, "Failed to write metadata"});\r
183 }\r
184 } else {\r
185 _hidl_cb(CommandResult{false, "Failed to read metadata"});\r
186 }\r
187 } else {\r
188 _hidl_cb(CommandResult{false, "Invalid slot"});\r
189 }\r
190\r
191 return Void();\r
192}\r
193\r
194Return<BoolResult> BootControl::isSlotBootable(uint32_t slot) {\r
195 bctl_metadata_t data;\r
196 BoolResult ret = BoolResult::FALSE;\r
197\r
198 if (slot < 2) {\r
199 if (readMetadata(data)) {\r
200 ret = static_cast<BoolResult>(data.slot_info[slot].bootable);\r
201 } else {\r
202 ret = BoolResult::FALSE;\r
203 }\r
204 } else {\r
205 ret = BoolResult::INVALID_SLOT;\r
206 }\r
207\r
208 return ret;\r
209}\r
210\r
211Return<BoolResult> BootControl::isSlotMarkedSuccessful(uint32_t slot) {\r
212 bctl_metadata_t data;\r
213 BoolResult ret = BoolResult::FALSE;\r
214\r
215 if (slot < 2) {\r
216 if (readMetadata(data)) {\r
217 ret = static_cast<BoolResult>(data.slot_info[slot].boot_successful);\r
218 } else {\r
219 ret = BoolResult::FALSE;\r
220 }\r
221 } else {\r
222 ret = BoolResult::INVALID_SLOT;\r
223 }\r
224\r
225 return ret;\r
226}\r
227\r
228Return<void> BootControl::getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) {\r
229 if (slot < 2) {\r
230 if (slot == 0) {\r
231 _hidl_cb(SLOT_SUFFIX_A);\r
232 } else {\r
233 _hidl_cb(SLOT_SUFFIX_B);\r
234 }\r
235 } else {\r
236 // default to slot A\r
237 _hidl_cb(SLOT_SUFFIX_A);\r
238 }\r
239\r
240 return Void();\r
241}\r
242\r
243} // namespace implementation\r
244} // namespace V1_0\r
245} // namespace boot\r
246} // namespace hardware\r
247} // namespace android\r