• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2020 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 #define LOG_TAG "bootcontrolhal"
18 
19 #include "BootControl.h"
20 
21 #include <android-base/file.h>
22 #include <android-base/unique_fd.h>
23 #include <bootloader_message/bootloader_message.h>
24 #include <cutils/properties.h>
25 #include <libboot_control/libboot_control.h>
26 #include <log/log.h>
27 
28 #include "DevInfo.h"
29 #include "GptUtils.h"
30 
31 namespace android {
32 namespace hardware {
33 namespace boot {
34 namespace V1_2 {
35 namespace implementation {
36 
37 using android::bootable::GetMiscVirtualAbMergeStatus;
38 using android::bootable::InitMiscVirtualAbMessageIfNeeded;
39 using android::bootable::SetMiscVirtualAbMergeStatus;
40 using android::hardware::boot::V1_0::BoolResult;
41 using android::hardware::boot::V1_0::CommandResult;
42 using android::hardware::boot::V1_1::MergeStatus;
43 
44 namespace {
45 
46 // clang-format off
47 
48 #define BOOT_A_PATH     "/dev/block/by-name/boot_a"
49 #define BOOT_B_PATH     "/dev/block/by-name/boot_b"
50 #define DEVINFO_PATH    "/dev/block/by-name/devinfo"
51 
52 #define BLOW_AR_PATH    "/sys/kernel/boot_control/blow_ar"
53 
54 // slot flags
55 #define AB_ATTR_PRIORITY_SHIFT      52
56 #define AB_ATTR_PRIORITY_MASK       (3UL << AB_ATTR_PRIORITY_SHIFT)
57 #define AB_ATTR_ACTIVE_SHIFT        54
58 #define AB_ATTR_ACTIVE              (1UL << AB_ATTR_ACTIVE_SHIFT)
59 #define AB_ATTR_RETRY_COUNT_SHIFT   (55)
60 #define AB_ATTR_RETRY_COUNT_MASK    (7UL << AB_ATTR_RETRY_COUNT_SHIFT)
61 #define AB_ATTR_SUCCESSFUL          (1UL << 58)
62 #define AB_ATTR_UNBOOTABLE          (1UL << 59)
63 
64 #define AB_ATTR_MAX_PRIORITY        3UL
65 #define AB_ATTR_MAX_RETRY_COUNT     3UL
66 
67 // clang-format on
68 
getDevPath(uint32_t slot)69 static std::string getDevPath(uint32_t slot) {
70     char real_path[PATH_MAX];
71 
72     const char *path = slot == 0 ? BOOT_A_PATH : BOOT_B_PATH;
73 
74     int ret = readlink(path, real_path, sizeof real_path);
75     if (ret < 0) {
76         ALOGE("readlink failed for boot device %s\n", strerror(errno));
77         return std::string();
78     }
79 
80     std::string dp(real_path);
81     // extract /dev/sda.. part
82     return dp.substr(0, sizeof "/dev/block/sdX" - 1);
83 }
84 
isSlotFlagSet(uint32_t slot,uint64_t flag)85 static bool isSlotFlagSet(uint32_t slot, uint64_t flag) {
86     std::string dev_path = getDevPath(slot);
87     if (dev_path.empty()) {
88         ALOGI("Could not get device path for slot %d\n", slot);
89         return false;
90     }
91 
92     GptUtils gpt(dev_path);
93     if (gpt.Load()) {
94         ALOGI("failed to load gpt data\n");
95         return false;
96     }
97 
98     gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a");
99     if (e == nullptr) {
100         ALOGI("failed to get gpt entry\n");
101         return false;
102     }
103 
104     return !!(e->attr & flag);
105 }
106 
setSlotFlag(uint32_t slot,uint64_t flag)107 static bool setSlotFlag(uint32_t slot, uint64_t flag) {
108     std::string dev_path = getDevPath(slot);
109     if (dev_path.empty()) {
110         ALOGI("Could not get device path for slot %d\n", slot);
111         return false;
112     }
113 
114     GptUtils gpt(dev_path);
115     if (gpt.Load()) {
116         ALOGI("failed to load gpt data\n");
117         return false;
118     }
119 
120     gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a");
121     if (e == nullptr) {
122         ALOGI("failed to get gpt entry\n");
123         return false;
124     }
125 
126     e->attr |= flag;
127     gpt.Sync();
128 
129     return true;
130 }
131 
132 static bool is_devinfo_valid;
133 static bool is_devinfo_initialized;
134 static std::mutex devinfo_lock;
135 static devinfo_t devinfo;
136 
isDevInfoValid()137 static bool isDevInfoValid() {
138     const std::lock_guard<std::mutex> lock(devinfo_lock);
139 
140     if (is_devinfo_initialized) {
141         return is_devinfo_valid;
142     }
143 
144     is_devinfo_initialized = true;
145 
146     android::base::unique_fd fd(open(DEVINFO_PATH, O_RDONLY));
147     android::base::ReadFully(fd, &devinfo, sizeof devinfo);
148 
149     if (devinfo.magic != DEVINFO_MAGIC) {
150         return is_devinfo_valid;
151     }
152 
153     uint32_t version = ((uint32_t)devinfo.ver_major << 16) | devinfo.ver_minor;
154     // only version 3.3+ supports A/B data
155     if (version >= 0x0003'0003) {
156         is_devinfo_valid = true;
157     }
158 
159     return is_devinfo_valid;
160 }
161 
DevInfoSync()162 static bool DevInfoSync() {
163     if (!isDevInfoValid()) {
164         return false;
165     }
166 
167     android::base::unique_fd fd(open(DEVINFO_PATH, O_WRONLY | O_DSYNC));
168     return android::base::WriteFully(fd, &devinfo, sizeof devinfo);
169 }
170 
DevInfoInitSlot(devinfo_ab_slot_data_t & slot_data)171 static void DevInfoInitSlot(devinfo_ab_slot_data_t &slot_data) {
172     slot_data.retry_count = AB_ATTR_MAX_RETRY_COUNT;
173     slot_data.unbootable = 0;
174     slot_data.successful = 0;
175     slot_data.active = 1;
176     slot_data.fastboot_ok = 0;
177 }
178 
blowAR()179 static bool blowAR() {
180     android::base::unique_fd fd(open(BLOW_AR_PATH, O_WRONLY | O_DSYNC));
181     return android::base::WriteStringToFd("1", fd);
182 }
183 
184 }  // namespace
185 
186 // Methods from ::android::hardware::boot::V1_0::IBootControl follow.
getNumberSlots()187 Return<uint32_t> BootControl::getNumberSlots() {
188     uint32_t slots = 0;
189 
190     if (access(BOOT_A_PATH, F_OK) == 0)
191         slots++;
192 
193     if (access(BOOT_B_PATH, F_OK) == 0)
194         slots++;
195 
196     return slots;
197 }
198 
getCurrentSlot()199 Return<uint32_t> BootControl::getCurrentSlot() {
200     char suffix[PROPERTY_VALUE_MAX];
201     property_get("ro.boot.slot_suffix", suffix, "_a");
202     return std::string(suffix) == "_b" ? 1 : 0;
203 }
204 
markBootSuccessful(markBootSuccessful_cb _hidl_cb)205 Return<void> BootControl::markBootSuccessful(markBootSuccessful_cb _hidl_cb) {
206     if (getNumberSlots() == 0) {
207         // no slots, just return true otherwise Android keeps trying
208         _hidl_cb({true, ""});
209         return Void();
210     }
211 
212     bool ret;
213     if (isDevInfoValid()) {
214         auto const slot = getCurrentSlot();
215         devinfo.ab_data.slots[slot].successful = 1;
216         ret = DevInfoSync();
217     } else {
218         ret = setSlotFlag(getCurrentSlot(), AB_ATTR_SUCCESSFUL);
219     }
220 
221     if (!ret) {
222         _hidl_cb({false, "Failed to set successful flag"});
223         return Void();
224     }
225 
226     if (!blowAR()) {
227         ALOGE("Failed to blow anti-rollback counter");
228         // Ignore the error, since ABL will re-trigger it on reboot
229     }
230 
231     _hidl_cb({true, ""});
232     return Void();
233 }
234 
setActiveBootSlot(uint32_t slot,setActiveBootSlot_cb _hidl_cb)235 Return<void> BootControl::setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) {
236     if (slot >= 2) {
237         _hidl_cb({false, "Invalid slot"});
238         return Void();
239     }
240 
241     if (isDevInfoValid()) {
242         auto &active_slot_data = devinfo.ab_data.slots[slot];
243         auto &inactive_slot_data = devinfo.ab_data.slots[!slot];
244 
245         inactive_slot_data.active = 0;
246         DevInfoInitSlot(active_slot_data);
247 
248         if (!DevInfoSync()) {
249             _hidl_cb({false, "Could not update DevInfo data"});
250             return Void();
251         }
252     } else {
253         std::string dev_path = getDevPath(slot);
254         if (dev_path.empty()) {
255             _hidl_cb({false, "Could not get device path for slot"});
256             return Void();
257         }
258 
259         GptUtils gpt(dev_path);
260         if (gpt.Load()) {
261             _hidl_cb({false, "failed to load gpt data"});
262             return Void();
263         }
264 
265         gpt_entry *active_entry = gpt.GetPartitionEntry(slot == 0 ? "boot_a" : "boot_b");
266         gpt_entry *inactive_entry = gpt.GetPartitionEntry(slot == 0 ? "boot_b" : "boot_a");
267         if (active_entry == nullptr || inactive_entry == nullptr) {
268             _hidl_cb({false, "failed to get entries for boot partitions"});
269             return Void();
270         }
271 
272         ALOGV("slot active attributes %lx\n", active_entry->attr);
273         ALOGV("slot inactive attributes %lx\n", inactive_entry->attr);
274 
275         // update attributes for active and inactive
276         inactive_entry->attr &= ~AB_ATTR_ACTIVE;
277         active_entry->attr = AB_ATTR_ACTIVE | (AB_ATTR_MAX_PRIORITY << AB_ATTR_PRIORITY_SHIFT) |
278                              (AB_ATTR_MAX_RETRY_COUNT << AB_ATTR_RETRY_COUNT_SHIFT);
279     }
280 
281     char boot_dev[PROPERTY_VALUE_MAX];
282     property_get("ro.boot.bootdevice", boot_dev, "");
283     if (boot_dev[0] == '\0') {
284         _hidl_cb({false, "invalid ro.boot.bootdevice prop"});
285         return Void();
286     }
287 
288     std::string boot_lun_path =
289             std::string("/sys/devices/platform/") + boot_dev + "/pixel/boot_lun_enabled";
290     int fd = open(boot_lun_path.c_str(), O_RDWR | O_DSYNC);
291     if (fd < 0) {
292         // Try old path for kernels < 5.4
293         // TODO: remove once kernel 4.19 support is deprecated
294         std::string boot_lun_path =
295                 std::string("/sys/devices/platform/") + boot_dev + "/attributes/boot_lun_enabled";
296         fd = open(boot_lun_path.c_str(), O_RDWR | O_DSYNC);
297         if (fd < 0) {
298             _hidl_cb({false, "failed to open ufs attr boot_lun_enabled"});
299             return Void();
300         }
301     }
302 
303     //
304     // bBootLunEn
305     // 0x1  => Boot LU A = enabled, Boot LU B = disable
306     // 0x2  => Boot LU A = disable, Boot LU B = enabled
307     //
308     int ret = android::base::WriteStringToFd(slot == 0 ? "1" : "2", fd);
309     close(fd);
310     if (ret < 0) {
311         _hidl_cb({false, "faied to write boot_lun_enabled attribute"});
312         return Void();
313     }
314 
315     _hidl_cb({true, ""});
316     return Void();
317 }
318 
setSlotAsUnbootable(uint32_t slot,setSlotAsUnbootable_cb _hidl_cb)319 Return<void> BootControl::setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) {
320     if (slot >= 2) {
321         _hidl_cb({false, "Invalid slot"});
322         return Void();
323     }
324 
325     if (isDevInfoValid()) {
326         auto &slot_data = devinfo.ab_data.slots[slot];
327         slot_data.unbootable = 1;
328         if (!DevInfoSync()) {
329             _hidl_cb({false, "Could not update DevInfo data"});
330             return Void();
331         }
332     } else {
333         std::string dev_path = getDevPath(slot);
334         if (dev_path.empty()) {
335             _hidl_cb({false, "Could not get device path for slot"});
336             return Void();
337         }
338 
339         GptUtils gpt(dev_path);
340         gpt.Load();
341 
342         gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a");
343         e->attr |= AB_ATTR_UNBOOTABLE;
344 
345         gpt.Sync();
346     }
347 
348     _hidl_cb({true, ""});
349     return Void();
350 }
351 
isSlotBootable(uint32_t slot)352 Return<::android::hardware::boot::V1_0::BoolResult> BootControl::isSlotBootable(uint32_t slot) {
353     if (getNumberSlots() == 0)
354         return BoolResult::FALSE;
355     if (slot >= getNumberSlots())
356         return BoolResult::INVALID_SLOT;
357 
358     bool unbootable;
359     if (isDevInfoValid()) {
360         auto &slot_data = devinfo.ab_data.slots[slot];
361         unbootable = !!slot_data.unbootable;
362     } else {
363         unbootable = isSlotFlagSet(slot, AB_ATTR_UNBOOTABLE);
364     }
365 
366     return unbootable ? BoolResult::FALSE : BoolResult::TRUE;
367 }
368 
isSlotMarkedSuccessful(uint32_t slot)369 Return<::android::hardware::boot::V1_0::BoolResult> BootControl::isSlotMarkedSuccessful(
370         uint32_t slot) {
371     if (getNumberSlots() == 0) {
372         // just return true so that we don't we another call trying to mark it as successful
373         // when there is no slots
374         return BoolResult::TRUE;
375     }
376     if (slot >= getNumberSlots())
377         return BoolResult::INVALID_SLOT;
378 
379     bool successful;
380     if (isDevInfoValid()) {
381         auto &slot_data = devinfo.ab_data.slots[slot];
382         successful = !!slot_data.successful;
383     } else {
384         successful = isSlotFlagSet(slot, AB_ATTR_SUCCESSFUL);
385     }
386 
387     return successful ? BoolResult::TRUE : BoolResult::FALSE;
388 }
389 
getSuffix(uint32_t slot,getSuffix_cb _hidl_cb)390 Return<void> BootControl::getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) {
391     _hidl_cb(slot == 0 ? "_a" : slot == 1 ? "_b" : "");
392     return Void();
393 }
394 
395 // Methods from ::android::hardware::boot::V1_1::IBootControl follow.
Init()396 bool BootControl::Init() {
397     return InitMiscVirtualAbMessageIfNeeded();
398 }
399 
setSnapshotMergeStatus(::android::hardware::boot::V1_1::MergeStatus status)400 Return<bool> BootControl::setSnapshotMergeStatus(
401         ::android::hardware::boot::V1_1::MergeStatus status) {
402     return SetMiscVirtualAbMergeStatus(getCurrentSlot(), status);
403 }
404 
getSnapshotMergeStatus()405 Return<::android::hardware::boot::V1_1::MergeStatus> BootControl::getSnapshotMergeStatus() {
406     MergeStatus status;
407     if (!GetMiscVirtualAbMergeStatus(getCurrentSlot(), &status)) {
408         return MergeStatus::UNKNOWN;
409     }
410     return status;
411 }
412 
413 // Methods from ::android::hardware::boot::V1_2::IBootControl follow.
getActiveBootSlot()414 Return<uint32_t> BootControl::getActiveBootSlot() {
415     if (getNumberSlots() == 0)
416         return 0;
417 
418     if (isDevInfoValid())
419         return devinfo.ab_data.slots[1].active ? 1 : 0;
420     return isSlotFlagSet(1, AB_ATTR_ACTIVE) ? 1 : 0;
421 }
422 
423 // Methods from ::android::hidl::base::V1_0::IBase follow.
424 
HIDL_FETCH_IBootControl(const char *)425 IBootControl *HIDL_FETCH_IBootControl(const char * /* name */) {
426     auto module = new BootControl();
427 
428     module->Init();
429 
430     return module;
431 }
432 
433 }  // namespace implementation
434 }  // namespace V1_2
435 }  // namespace boot
436 }  // namespace hardware
437 }  // namespace android
438