diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-06 00:05:27 +0000 |
---|---|---|
committer | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2023-12-06 00:05:27 +0000 |
commit | bfb557b32a52925ad7d5c308244d01fe30eb8b28 (patch) | |
tree | 6092cf1637016f2b7f24bab425be506c57ae1d90 | |
parent | 7be45da460dc01f75f79b5d957fdf981ea37821c (diff) | |
parent | 1dc0d70de428d535eb3d810619933663743d5f7f (diff) | |
download | zuma-bfb557b32a52925ad7d5c308244d01fe30eb8b28.tar.gz |
Snap for 11180250 from 1dc0d70de428d535eb3d810619933663743d5f7f to 24Q1-release
Change-Id: I670e414a427adc4ab7c9f0b3e51808918de8218c
31 files changed, 280 insertions, 3420 deletions
@@ -40,6 +40,7 @@ include device/google/gs-common/widevine/widevine.mk include device/google/gs-common/sota_app/factoryota.mk include device/google/gs-common/misc_writer/misc_writer.mk include device/google/gs-common/gyotaku_app/gyotaku.mk +include device/google/gs-common/bootctrl/bootctrl_aidl.mk include device/google/zuma/dumpstate/item.mk @@ -924,11 +925,6 @@ PRODUCT_PACKAGES += \ ImsMediaService \ libimsmedia -# Boot Control HAL -PRODUCT_PACKAGES += \ - android.hardware.boot-service.default-zuma\ - android.hardware.boot-service.default_recovery-zuma - # Exynos RIL and telephony # Multi SIM(DSDS) SIM_COUNT := 2 diff --git a/interfaces/boot/1.0/Android.bp b/interfaces/boot/1.0/Android.bp deleted file mode 100644 index 5599faf..0000000 --- a/interfaces/boot/1.0/Android.bp +++ /dev/null @@ -1,66 +0,0 @@ -// -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "//device/google/zuma:device_google_zuma_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: [ - "//device/google/zuma:device_google_zuma_license", - ], -} - -cc_binary { - name: "android.hardware.boot@1.0-service-zuma", - defaults: ["hidl_defaults"], - relative_install_path: "hw", - vendor: true, - init_rc: ["android.hardware.boot@1.0-service-zuma.rc"], - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - "service.cpp" - ], - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libutils", - "libcutils", - "libz", - "android.hardware.boot@1.0", - ], -} - -cc_library { - name: "android.hardware.boot@1.0-impl-zuma", - recovery: true, - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - ], - relative_install_path: "hw", - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libutils", - "libcutils", - "libz", - "android.hardware.boot@1.0", - ], -} diff --git a/interfaces/boot/1.0/BootControl.cpp b/interfaces/boot/1.0/BootControl.cpp deleted file mode 100644 index 1f155c9..0000000 --- a/interfaces/boot/1.0/BootControl.cpp +++ /dev/null @@ -1,272 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "bootcontrolhal" - -#include "BootControl.h" -#include "GptUtils.h" - -#include <android-base/file.h> -#include <cutils/properties.h> -#include <log/log.h> - -namespace android { -namespace hardware { -namespace boot { -namespace V1_0 { -namespace implementation { - -namespace { - -#define BOOT_A_PATH "/dev/block/by-name/boot_a" -#define BOOT_B_PATH "/dev/block/by-name/boot_b" - -// slot flags -#define AB_ATTR_PRIORITY_SHIFT 52 -#define AB_ATTR_PRIORITY_MASK (3UL << AB_ATTR_PRIORITY_SHIFT) -#define AB_ATTR_ACTIVE_SHIFT 54 -#define AB_ATTR_ACTIVE (1UL << AB_ATTR_ACTIVE_SHIFT) -#define AB_ATTR_RETRY_COUNT_SHIFT (55) -#define AB_ATTR_RETRY_COUNT_MASK (7UL << AB_ATTR_RETRY_COUNT_SHIFT) -#define AB_ATTR_SUCCESSFUL (1UL << 58) -#define AB_ATTR_UNBOOTABLE (1UL << 59) - -#define AB_ATTR_MAX_PRIORITY 3UL -#define AB_ATTR_MAX_RETRY_COUNT 3UL - -static std::string getDevPath(uint32_t slot) { - char real_path[PATH_MAX]; - - const char *path = slot == 0 ? BOOT_A_PATH : BOOT_B_PATH; - - int ret = readlink(path, real_path, sizeof real_path); - if (ret < 0) { - ALOGE("readlink failed for boot device %s\n", strerror(errno)); - return std::string(); - } - - std::string dp(real_path); - // extract /dev/sda.. part - return dp.substr(0, sizeof "/dev/block/sdX" - 1); -} - -static bool isSlotFlagSet(uint32_t slot, uint64_t flag) { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - ALOGI("Could not get device path for slot %d\n", slot); - return false; - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - ALOGI("failed to load gpt data\n"); - return false; - } - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - if (e == nullptr) { - ALOGI("failed to get gpt entry\n"); - return false; - } - - return !!(e->attr & flag); -} - -static int setSlotFlag(uint32_t slot, uint64_t flag) { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - ALOGI("Could not get device path for slot %d\n", slot); - return -1; - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - ALOGI("failed to load gpt data\n"); - return -1; - } - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - if (e == nullptr) { - ALOGI("failed to get gpt entry\n"); - return -1; - } - - e->attr |= flag; - gpt.Sync(); - - return 0; -} - -} - -// Methods from ::android::hardware::boot::V1_0::IBootControl follow. -Return<uint32_t> BootControl::getNumberSlots() { - uint32_t slots = 0; - - if (access(BOOT_A_PATH, F_OK) == 0) - slots++; - - if (access(BOOT_B_PATH, F_OK) == 0) - slots++; - - return slots; -} - -Return<uint32_t> BootControl::getCurrentSlot() { - char suffix[PROPERTY_VALUE_MAX]; - property_get("ro.boot.slot_suffix", suffix, "_a"); - return std::string(suffix) == "_b" ? 1 : 0; -} - -Return<void> BootControl::markBootSuccessful(markBootSuccessful_cb _hidl_cb) { - if (getNumberSlots() == 0) { - // no slots, just return true otherwise Android keeps trying - _hidl_cb({true, ""}); - return Void(); - } - int ret = setSlotFlag(getCurrentSlot(), AB_ATTR_SUCCESSFUL); - ret ? _hidl_cb({false, "Failed to set successfull flag"}) : _hidl_cb({true, ""}); - return Void(); -} - -Return<void> BootControl::setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) { - if (slot >= 2) { - _hidl_cb({false, "Invalid slot"}); - return Void(); - } - - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - _hidl_cb({false, "Could not get device path for slot"}); - return Void(); - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - _hidl_cb({false, "failed to load gpt data"}); - return Void(); - } - - gpt_entry *active_entry = gpt.GetPartitionEntry(slot == 0 ? "boot_a" : "boot_b"); - gpt_entry *inactive_entry = gpt.GetPartitionEntry(slot == 0 ? "boot_b" : "boot_a"); - if (active_entry == nullptr || inactive_entry == nullptr) { - _hidl_cb({false, "failed to get entries for boot partitions"}); - return Void(); - } - - ALOGV("slot active attributes %lx\n", active_entry->attr); - ALOGV("slot inactive attributes %lx\n", inactive_entry->attr); - - char boot_dev[PROPERTY_VALUE_MAX]; - property_get("ro.boot.bootdevice", boot_dev, ""); - if (boot_dev[0] == '\0') { - _hidl_cb({false, "invalid ro.boot.bootdevice prop"}); - return Void(); - } - - std::string boot_lun_path = std::string("/sys/devices/platform/") + - boot_dev + "/pixel/boot_lun_enabled"; - int fd = open(boot_lun_path.c_str(), O_RDWR); - if (fd < 0) { - // Try old path for kernels < 5.4 - // TODO: remove once kernel 4.19 support is deprecated - std::string boot_lun_path = std::string("/sys/devices/platform/") + - boot_dev + "/attributes/boot_lun_enabled"; - fd = open(boot_lun_path.c_str(), O_RDWR); - if (fd < 0) { - _hidl_cb({false, "failed to open ufs attr boot_lun_enabled"}); - return Void(); - } - } - - // update attributes for active and inactive - inactive_entry->attr &= ~AB_ATTR_ACTIVE; - active_entry->attr = AB_ATTR_ACTIVE | (AB_ATTR_MAX_PRIORITY << AB_ATTR_PRIORITY_SHIFT) | - (AB_ATTR_MAX_RETRY_COUNT << AB_ATTR_RETRY_COUNT_SHIFT); - - // - // bBootLunEn - // 0x1 => Boot LU A = enabled, Boot LU B = disable - // 0x2 => Boot LU A = disable, Boot LU B = enabled - // - int ret = android::base::WriteStringToFd(slot == 0 ? "1" : "2", fd); - close(fd); - if (ret < 0) { - _hidl_cb({false, "faied to write boot_lun_enabled attribute"}); - return Void(); - } - - _hidl_cb({true, ""}); - return Void(); -} - -Return<void> BootControl::setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) { - if (slot >= 2) { - _hidl_cb({false, "Invalid slot"}); - return Void(); - } - - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - _hidl_cb({false, "Could not get device path for slot"}); - return Void(); - } - - GptUtils gpt(dev_path); - gpt.Load(); - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - e->attr |= AB_ATTR_UNBOOTABLE; - - gpt.Sync(); - - _hidl_cb({true, ""}); - return Void(); -} - -Return<::android::hardware::boot::V1_0::BoolResult> BootControl::isSlotBootable(uint32_t slot) { - if (getNumberSlots() == 0) - return BoolResult::FALSE; - if (slot >= getNumberSlots()) - return BoolResult::INVALID_SLOT; - return isSlotFlagSet(slot, AB_ATTR_UNBOOTABLE) ? BoolResult::FALSE : BoolResult::TRUE; -} - -Return<::android::hardware::boot::V1_0::BoolResult> BootControl::isSlotMarkedSuccessful(uint32_t slot) { - if (getNumberSlots() == 0) { - // just return true so that we don't we another call trying to mark it as successful - // when there is no slots - return BoolResult::TRUE; - } - if (slot >= getNumberSlots()) - return BoolResult::INVALID_SLOT; - return isSlotFlagSet(slot, AB_ATTR_SUCCESSFUL) ? BoolResult::TRUE : BoolResult::FALSE; -} - -Return<void> BootControl::getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) { - _hidl_cb(slot == 0 ? "_a" : slot == 1 ? "_b" : ""); - return Void(); -} - -extern "C" IBootControl* HIDL_FETCH_IBootControl(const char*) { - return new BootControl(); -} - -} // namespace implementation -} // namespace V1_0 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.0/BootControl.h b/interfaces/boot/1.0/BootControl.h deleted file mode 100644 index eb81cb0..0000000 --- a/interfaces/boot/1.0/BootControl.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <android/hardware/boot/1.0/IBootControl.h> -#include <hidl/MQDescriptor.h> -#include <hidl/Status.h> - -namespace android { -namespace hardware { -namespace boot { -namespace V1_0 { -namespace implementation { - -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; -using ::android::hardware::Void; -using ::android::sp; - -struct BootControl : public IBootControl { - // Methods from ::android::hardware::boot::V1_0::IBootControl follow. - Return<uint32_t> getNumberSlots() override; - Return<uint32_t> getCurrentSlot() override; - Return<void> markBootSuccessful(markBootSuccessful_cb _hidl_cb) override; - Return<void> setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) override; - Return<void> setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) override; - Return<::android::hardware::boot::V1_0::BoolResult> isSlotBootable(uint32_t slot) override; - Return<::android::hardware::boot::V1_0::BoolResult> isSlotMarkedSuccessful(uint32_t slot) override; - Return<void> getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) override; - - // Methods from ::android::hidl::base::V1_0::IBase follow. - -}; - -// FIXME: most likely delete, this is only for passthrough implementations -extern "C" IBootControl* HIDL_FETCH_IBootControl(const char* name); - -} // namespace implementation -} // namespace V1_0 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.0/GptUtils.cpp b/interfaces/boot/1.0/GptUtils.cpp deleted file mode 100644 index f893617..0000000 --- a/interfaces/boot/1.0/GptUtils.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "bootcontrolhal" - -#include "GptUtils.h" - -#include <errno.h> -#include <log/log.h> -#include <android-base/file.h> -#include <linux/fs.h> -#include <zlib.h> - -namespace android { -namespace hardware { -namespace boot { -namespace V1_0 { -namespace implementation { - -namespace { - -static int ValidateGptHeader(gpt_header *gpt) -{ - if (gpt->signature != GPT_SIGNATURE) { - ALOGE("invalid gpt signature 0x%lx\n", gpt->signature); - return -1; - } - - if (gpt->header_size != sizeof(gpt_header)) { - ALOGE("invalid gpt header size %u\n", gpt->header_size); - return -1; - } - - if (gpt->entry_size != sizeof(gpt_entry)) { - ALOGE("invalid gpt entry size %u\n", gpt->entry_size); - return -1; - } - - return 0; -} - -} - -GptUtils::GptUtils(const std::string dev_path) : dev_path(dev_path), fd(0) {} - -int GptUtils::Load(void) -{ - fd = open(dev_path.c_str(), O_RDWR); - if (fd < 0) { - ALOGE("failed to open block dev %s, %d\n", dev_path.c_str(), errno); - return -1; - } - - int ret = ioctl(fd, BLKSSZGET, &block_size); - if (ret < 0) { - ALOGE("failed to get block size %d\n", errno); - return -1; - } - - // read primary header - lseek64(fd, block_size, SEEK_SET); - ret = read(fd, &gpt_primary, sizeof gpt_primary); - if (ret < 0) { - ALOGE("failed to read gpt primary header %d\n", errno); - return -1; - } - - if (ValidateGptHeader(&gpt_primary)) { - ALOGE("error validating gpt header\n"); - return -1; - } - - // read partition entries - entry_array.resize(gpt_primary.entry_count); - uint32_t entries_size = gpt_primary.entry_size * gpt_primary.entry_count; - lseek64(fd, block_size * gpt_primary.start_lba, SEEK_SET); - ret = read(fd, entry_array.data(), entries_size); - if (ret < 0) { - ALOGE("failed to read gpt partition entries %d\n", errno); - return -1; - } - - // read gpt back header - lseek64(fd, block_size * gpt_primary.backup_lba, SEEK_SET); - ret = read(fd, &gpt_backup, sizeof gpt_backup); - if (ret < 0) { - ALOGE("failed to read gpt backup header %d\n", errno); - return -1; - } - - if (ValidateGptHeader(&gpt_backup)) { - ALOGW("error validating gpt backup\n"); // just warn about it, not fail - } - - // Create map <partition name, gpt_entry pointer> - auto get_name = [](const uint16_t *efi_name) { - char name[37] = {}; - for (int i = 0; efi_name[i] && i < sizeof name - 1; ++i) - name[i] = efi_name[i]; - return std::string(name); - }; - - for (auto const &e: entry_array) { - if (e.name[0] == 0) - break; // stop at the first partition with no name - std::string s = get_name(e.name); - entries[s] = const_cast<gpt_entry *>(&e); - } - - return 0; -} - -gpt_entry *GptUtils::GetPartitionEntry(std::string name) -{ - return entries.find(name) != entries.end() ? entries[name] : nullptr; -} - -int GptUtils::Sync(void) -{ - if (!fd) - return -1; - - // calculate crc and check if we need to update gpt - gpt_primary.entries_crc32 = crc32(0, reinterpret_cast<uint8_t *>(entry_array.data()), - entry_array.size() * sizeof(gpt_entry)); - - // save old crc - uint32_t crc = gpt_primary.crc32; - gpt_primary.crc32 = 0; - - gpt_primary.crc32 = crc32(0, reinterpret_cast<uint8_t *>(&gpt_primary), sizeof gpt_primary); - if (crc == gpt_primary.crc32) - return 0; // nothing to do (no changes) - - ALOGI("updating GPT\n"); - - lseek64(fd, block_size * gpt_primary.current_lba, SEEK_SET); - int ret = write(fd, &gpt_primary, sizeof gpt_primary); - if (ret < 0) { - ALOGE("failed to write gpt primary header %d\n", errno); - return -1; - } - - lseek64(fd, block_size * gpt_primary.start_lba, SEEK_SET); - ret = write(fd, entry_array.data(), entry_array.size() * sizeof(gpt_entry)); - if (ret < 0) { - ALOGE("failed to write gpt partition entries %d\n", errno); - return -1; - } - - //update GPT backup entries and backup - lseek64(fd, block_size * gpt_backup.start_lba, SEEK_SET); - ret = write(fd, entry_array.data(), entry_array.size() * sizeof(gpt_entry)); - if (ret < 0) { - ALOGE("failed to write gpt backup partition entries %d\n", errno); - return -1; - } - - gpt_backup.entries_crc32 = gpt_primary.entries_crc32; - gpt_backup.crc32 = 0; - gpt_backup.crc32 = crc32(0, reinterpret_cast<uint8_t *>(&gpt_backup), sizeof gpt_backup); - lseek64(fd, block_size * gpt_primary.backup_lba, SEEK_SET); - ret = write(fd, &gpt_backup, sizeof gpt_backup); - if (ret < 0) { - ALOGE("failed to write gpt backup header %d\n", errno); - return -1; - } - - fsync(fd); - - return 0; -} - -GptUtils::~GptUtils() -{ - if (fd) { - Sync(); - close(fd); - } -} - -} // namespace implementation -} // namespace V1_0 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.0/GptUtils.h b/interfaces/boot/1.0/GptUtils.h deleted file mode 100644 index d969d9d..0000000 --- a/interfaces/boot/1.0/GptUtils.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <string> -#include <vector> -#include <map> - -namespace android { -namespace hardware { -namespace boot { -namespace V1_0 { -namespace implementation { - -#define GPT_SIGNATURE 0x5452415020494645UL - -typedef struct { - uint8_t type_guid[16]; - uint8_t guid[16]; - uint64_t first_lba; - uint64_t last_lba; - uint64_t attr; - uint16_t name[36]; -} __attribute__((packed)) gpt_entry; - -typedef struct { - uint64_t signature; - uint32_t revision; - uint32_t header_size; - uint32_t crc32; - uint32_t reserved; - uint64_t current_lba; - uint64_t backup_lba; - uint64_t first_usable_lba; - uint64_t last_usable_lba; - uint8_t disk_guid[16]; - uint64_t start_lba; - uint32_t entry_count; - uint32_t entry_size; - uint32_t entries_crc32; -} __attribute__((packed)) gpt_header; - -class GptUtils { - public: - GptUtils(const std::string dev_path); - int Load(void); - gpt_entry *GetPartitionEntry(std::string name); - int Sync(void); - ~GptUtils(); - - private: - std::string dev_path; - int fd; - uint32_t block_size; - gpt_header gpt_primary; - gpt_header gpt_backup; - std::vector<gpt_entry> entry_array; - std::map<std::string, gpt_entry *>entries; -}; - -} // namespace implementation -} // namespace V1_0 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.0/android.hardware.boot@1.0-service-zuma.rc b/interfaces/boot/1.0/android.hardware.boot@1.0-service-zuma.rc deleted file mode 100644 index 7997fde..0000000 --- a/interfaces/boot/1.0/android.hardware.boot@1.0-service-zuma.rc +++ /dev/null @@ -1,4 +0,0 @@ -service vendor.boot-hal-1-0 /vendor/bin/hw/android.hardware.boot@1.0-service-zuma - class early_hal - user root - group root diff --git a/interfaces/boot/1.0/service.cpp b/interfaces/boot/1.0/service.cpp deleted file mode 100644 index 9dcd78c..0000000 --- a/interfaces/boot/1.0/service.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#define LOG_TAG "android.hardware.boot@1.0-service" - -#include <log/log.h> -#include <hidl/HidlTransportSupport.h> -#include <hidl/Status.h> -#include <android/hardware/boot/1.0/IBootControl.h> -#include "BootControl.h" - -using ::android::status_t; - -using ::android::hardware::boot::V1_0::IBootControl; - -using ::android::hardware::boot::V1_0::implementation::BootControl; - -int main (int /* argc */, char * /* argv */ []) { - // This function must be called before you join to ensure the proper - // number of threads are created. The threadpool will never exceed - // size one because of this call. - ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/); - - ::android::sp bootctrl = new BootControl(); - const status_t status = bootctrl->registerAsService(); - if (status != ::android::OK) { - return 1; // or handle error - } - - // Adds this thread to the threadpool, resulting in one total - // thread in the threadpool. We could also do other things, but - // would have to specify 'false' to willJoin in configureRpcThreadpool. - ::android::hardware::joinRpcThreadpool(); - return 1; // joinRpcThreadpool should never return -} diff --git a/interfaces/boot/1.2/Android.bp b/interfaces/boot/1.2/Android.bp deleted file mode 100644 index 90b0c6e..0000000 --- a/interfaces/boot/1.2/Android.bp +++ /dev/null @@ -1,83 +0,0 @@ -// -// Copyright (C) 2020 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "//device/google/zuma:device_google_zuma_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: [ - "//device/google/zuma:device_google_zuma_license", - ], -} - -cc_binary { - name: "android.hardware.boot@1.2-service-zuma", - defaults: ["hidl_defaults"], - relative_install_path: "hw", - vendor: true, - init_rc: ["android.hardware.boot@1.2-service-zuma.rc"], - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - "service.cpp" - ], - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libutils", - "libcutils", - "libz", - "libtrusty", - "android.hardware.boot@1.0", - "android.hardware.boot@1.1", - "android.hardware.boot@1.2", - ], - static_libs: [ - "libboot_control", - "libbootloader_message_vendor", - "libfstab", - ], -} - -cc_library { - name: "android.hardware.boot@1.2-impl-zuma", - stem: "android.hardware.boot@1.0-impl-1.2-impl-zuma", - recovery: true, - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - ], - relative_install_path: "hw", - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libutils", - "libcutils", - "libz", - "libtrusty", - "android.hardware.boot@1.0", - "android.hardware.boot@1.1", - "android.hardware.boot@1.2", - ], - static_libs: [ - "libboot_control", - "libbootloader_message_vendor", - "libfstab", - ], -} diff --git a/interfaces/boot/1.2/BootControl.cpp b/interfaces/boot/1.2/BootControl.cpp deleted file mode 100644 index 7782075..0000000 --- a/interfaces/boot/1.2/BootControl.cpp +++ /dev/null @@ -1,501 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "bootcontrolhal" - -#include "BootControl.h" - -#include <android-base/file.h> -#include <android-base/unique_fd.h> -#include <bootloader_message/bootloader_message.h> -#include <cutils/properties.h> -#include <libboot_control/libboot_control.h> -#include <log/log.h> -#include <trusty/tipc.h> - -#include "DevInfo.h" -#include "GptUtils.h" - -namespace android { -namespace hardware { -namespace boot { -namespace V1_2 { -namespace implementation { - -using android::bootable::GetMiscVirtualAbMergeStatus; -using android::bootable::InitMiscVirtualAbMessageIfNeeded; -using android::bootable::SetMiscVirtualAbMergeStatus; -using android::hardware::boot::V1_0::BoolResult; -using android::hardware::boot::V1_0::CommandResult; -using android::hardware::boot::V1_1::MergeStatus; - -namespace { - -// clang-format off - -#define BOOT_A_PATH "/dev/block/by-name/boot_a" -#define BOOT_B_PATH "/dev/block/by-name/boot_b" -#define DEVINFO_PATH "/dev/block/by-name/devinfo" - -// slot flags -#define AB_ATTR_PRIORITY_SHIFT 52 -#define AB_ATTR_PRIORITY_MASK (3UL << AB_ATTR_PRIORITY_SHIFT) -#define AB_ATTR_ACTIVE_SHIFT 54 -#define AB_ATTR_ACTIVE (1UL << AB_ATTR_ACTIVE_SHIFT) -#define AB_ATTR_RETRY_COUNT_SHIFT (55) -#define AB_ATTR_RETRY_COUNT_MASK (7UL << AB_ATTR_RETRY_COUNT_SHIFT) -#define AB_ATTR_SUCCESSFUL (1UL << 58) -#define AB_ATTR_UNBOOTABLE (1UL << 59) - -#define AB_ATTR_MAX_PRIORITY 3UL -#define AB_ATTR_MAX_RETRY_COUNT 3UL - -// clang-format on - -static std::string getDevPath(uint32_t slot) { - char real_path[PATH_MAX]; - - const char *path = slot == 0 ? BOOT_A_PATH : BOOT_B_PATH; - - int ret = readlink(path, real_path, sizeof real_path); - if (ret < 0) { - ALOGE("readlink failed for boot device %s\n", strerror(errno)); - return std::string(); - } - - std::string dp(real_path); - // extract /dev/sda.. part - return dp.substr(0, sizeof "/dev/block/sdX" - 1); -} - -static bool isSlotFlagSet(uint32_t slot, uint64_t flag) { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - ALOGI("Could not get device path for slot %d\n", slot); - return false; - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - ALOGI("failed to load gpt data\n"); - return false; - } - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - if (e == nullptr) { - ALOGI("failed to get gpt entry\n"); - return false; - } - - return !!(e->attr & flag); -} - -static bool setSlotFlag(uint32_t slot, uint64_t flag) { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - ALOGI("Could not get device path for slot %d\n", slot); - return false; - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - ALOGI("failed to load gpt data\n"); - return false; - } - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - if (e == nullptr) { - ALOGI("failed to get gpt entry\n"); - return false; - } - - e->attr |= flag; - gpt.Sync(); - - return true; -} - -static bool is_devinfo_valid; -static bool is_devinfo_initialized; -static std::mutex devinfo_lock; -static devinfo_t devinfo; - -static bool isDevInfoValid() { - const std::lock_guard<std::mutex> lock(devinfo_lock); - - if (is_devinfo_initialized) { - return is_devinfo_valid; - } - - is_devinfo_initialized = true; - - android::base::unique_fd fd(open(DEVINFO_PATH, O_RDONLY)); - android::base::ReadFully(fd, &devinfo, sizeof devinfo); - - if (devinfo.magic != DEVINFO_MAGIC) { - return is_devinfo_valid; - } - - uint32_t version = ((uint32_t)devinfo.ver_major << 16) | devinfo.ver_minor; - // only version 3.3+ supports A/B data - if (version >= 0x0003'0003) { - is_devinfo_valid = true; - } - - return is_devinfo_valid; -} - -static bool DevInfoSync() { - if (!isDevInfoValid()) { - return false; - } - - android::base::unique_fd fd(open(DEVINFO_PATH, O_WRONLY | O_DSYNC)); - return android::base::WriteFully(fd, &devinfo, sizeof devinfo); -} - -static void DevInfoInitSlot(devinfo_ab_slot_data_t &slot_data) { - slot_data.retry_count = AB_ATTR_MAX_RETRY_COUNT; - slot_data.unbootable = 0; - slot_data.successful = 0; - slot_data.active = 1; - slot_data.fastboot_ok = 0; -} - -static int blow_otp_AR(bool secure) { - static const char *dev_name = "/dev/trusty-ipc-dev0"; - static const char *otp_name = "com.android.trusty.otp_manager.tidl"; - int fd = 1, ret = 0; - uint32_t cmd = secure? OTP_CMD_write_antirbk_secure_ap : OTP_CMD_write_antirbk_non_secure_ap; - fd = tipc_connect(dev_name, otp_name); - if (fd < 0) { - ALOGI("Failed to connect to OTP_MGR ns TA - is it missing?\n"); - ret = -1; - return ret; - } - - struct otp_mgr_req_base req = { - .command = cmd, - .resp_payload_size = 0, - }; - struct iovec iov[] = { - { - .iov_base = &req, - .iov_len = sizeof(req), - }, - }; - - int rc = tipc_send(fd, iov, 1, NULL, 0); - if (rc != sizeof(req)) { - ALOGI("Send fail! %x\n", rc); - return rc; - } - - struct otp_mgr_rsp_base resp; - rc = read(fd, &resp, sizeof(resp)); - if (rc < 0) { - ALOGI("Read fail! %x\n", rc); - return rc; - } - - if (rc < sizeof(resp)) { - ALOGI("Not enough data! %x\n", rc); - return -EIO; - } - - if (resp.command != (cmd | OTP_RESP_BIT)) { - ALOGI("Wrong command! %x\n", resp.command); - return -EINVAL; - } - - if (resp.result != 0) { - fprintf(stderr, "AR writing error! %x\n", resp.result); - return -EINVAL; - } - - tipc_close(fd); - return 0; -} - -static bool blowAR() { - int ret = blow_otp_AR(true); - if (ret) { - ALOGI("Blow secure anti-rollback OTP failed"); - return false; - } - - ret = blow_otp_AR(false); - if (ret) { - ALOGI("Blow non-secure anti-rollback OTP failed"); - return false; - } - - return true; -} -} // namespace - -// Methods from ::android::hardware::boot::V1_0::IBootControl follow. -Return<uint32_t> BootControl::getNumberSlots() { - uint32_t slots = 0; - - if (access(BOOT_A_PATH, F_OK) == 0) - slots++; - - if (access(BOOT_B_PATH, F_OK) == 0) - slots++; - - return slots; -} - -Return<uint32_t> BootControl::getCurrentSlot() { - char suffix[PROPERTY_VALUE_MAX]; - property_get("ro.boot.slot_suffix", suffix, "_a"); - return std::string(suffix) == "_b" ? 1 : 0; -} - -Return<void> BootControl::markBootSuccessful(markBootSuccessful_cb _hidl_cb) { - if (getNumberSlots() == 0) { - // no slots, just return true otherwise Android keeps trying - _hidl_cb({true, ""}); - return Void(); - } - - bool ret; - if (isDevInfoValid()) { - auto const slot = getCurrentSlot(); - devinfo.ab_data.slots[slot].successful = 1; - ret = DevInfoSync(); - } else { - ret = setSlotFlag(getCurrentSlot(), AB_ATTR_SUCCESSFUL); - } - - if (!ret) { - _hidl_cb({false, "Failed to set successful flag"}); - return Void(); - } - - if (!blowAR()) { - ALOGE("Failed to blow anti-rollback counter"); - // Ignore the error, since ABL will re-trigger it on reboot - } - - _hidl_cb({true, ""}); - return Void(); -} - -Return<void> BootControl::setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) { - if (slot >= 2) { - _hidl_cb({false, "Invalid slot"}); - return Void(); - } - - if (isDevInfoValid()) { - auto &active_slot_data = devinfo.ab_data.slots[slot]; - auto &inactive_slot_data = devinfo.ab_data.slots[!slot]; - - inactive_slot_data.active = 0; - DevInfoInitSlot(active_slot_data); - - if (!DevInfoSync()) { - _hidl_cb({false, "Could not update DevInfo data"}); - return Void(); - } - } else { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - _hidl_cb({false, "Could not get device path for slot"}); - return Void(); - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - _hidl_cb({false, "failed to load gpt data"}); - return Void(); - } - - gpt_entry *active_entry = gpt.GetPartitionEntry(slot == 0 ? "boot_a" : "boot_b"); - gpt_entry *inactive_entry = gpt.GetPartitionEntry(slot == 0 ? "boot_b" : "boot_a"); - if (active_entry == nullptr || inactive_entry == nullptr) { - _hidl_cb({false, "failed to get entries for boot partitions"}); - return Void(); - } - - ALOGV("slot active attributes %lx\n", active_entry->attr); - ALOGV("slot inactive attributes %lx\n", inactive_entry->attr); - - // update attributes for active and inactive - inactive_entry->attr &= ~AB_ATTR_ACTIVE; - active_entry->attr = AB_ATTR_ACTIVE | (AB_ATTR_MAX_PRIORITY << AB_ATTR_PRIORITY_SHIFT) | - (AB_ATTR_MAX_RETRY_COUNT << AB_ATTR_RETRY_COUNT_SHIFT); - } - - char boot_dev[PROPERTY_VALUE_MAX]; - property_get("ro.boot.bootdevice", boot_dev, ""); - if (boot_dev[0] == '\0') { - _hidl_cb({false, "invalid ro.boot.bootdevice prop"}); - return Void(); - } - - std::string boot_lun_path = - std::string("/sys/devices/platform/") + boot_dev + "/pixel/boot_lun_enabled"; - int fd = open(boot_lun_path.c_str(), O_RDWR | O_DSYNC); - if (fd < 0) { - // Try old path for kernels < 5.4 - // TODO: remove once kernel 4.19 support is deprecated - std::string boot_lun_path = - std::string("/sys/devices/platform/") + boot_dev + "/attributes/boot_lun_enabled"; - fd = open(boot_lun_path.c_str(), O_RDWR | O_DSYNC); - if (fd < 0) { - _hidl_cb({false, "failed to open ufs attr boot_lun_enabled"}); - return Void(); - } - } - - // - // bBootLunEn - // 0x1 => Boot LU A = enabled, Boot LU B = disable - // 0x2 => Boot LU A = disable, Boot LU B = enabled - // - int ret = android::base::WriteStringToFd(slot == 0 ? "1" : "2", fd); - close(fd); - if (ret < 0) { - _hidl_cb({false, "faied to write boot_lun_enabled attribute"}); - return Void(); - } - - _hidl_cb({true, ""}); - return Void(); -} - -Return<void> BootControl::setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) { - if (slot >= 2) { - _hidl_cb({false, "Invalid slot"}); - return Void(); - } - - if (isDevInfoValid()) { - auto &slot_data = devinfo.ab_data.slots[slot]; - slot_data.unbootable = 1; - if (!DevInfoSync()) { - _hidl_cb({false, "Could not update DevInfo data"}); - return Void(); - } - } else { - std::string dev_path = getDevPath(slot); - if (dev_path.empty()) { - _hidl_cb({false, "Could not get device path for slot"}); - return Void(); - } - - GptUtils gpt(dev_path); - gpt.Load(); - - gpt_entry *e = gpt.GetPartitionEntry(slot ? "boot_b" : "boot_a"); - e->attr |= AB_ATTR_UNBOOTABLE; - - gpt.Sync(); - } - - _hidl_cb({true, ""}); - return Void(); -} - -Return<::android::hardware::boot::V1_0::BoolResult> BootControl::isSlotBootable(uint32_t slot) { - if (getNumberSlots() == 0) - return BoolResult::FALSE; - if (slot >= getNumberSlots()) - return BoolResult::INVALID_SLOT; - - bool unbootable; - if (isDevInfoValid()) { - auto &slot_data = devinfo.ab_data.slots[slot]; - unbootable = !!slot_data.unbootable; - } else { - unbootable = isSlotFlagSet(slot, AB_ATTR_UNBOOTABLE); - } - - return unbootable ? BoolResult::FALSE : BoolResult::TRUE; -} - -Return<::android::hardware::boot::V1_0::BoolResult> BootControl::isSlotMarkedSuccessful( - uint32_t slot) { - if (getNumberSlots() == 0) { - // just return true so that we don't we another call trying to mark it as successful - // when there is no slots - return BoolResult::TRUE; - } - if (slot >= getNumberSlots()) - return BoolResult::INVALID_SLOT; - - bool successful; - if (isDevInfoValid()) { - auto &slot_data = devinfo.ab_data.slots[slot]; - successful = !!slot_data.successful; - } else { - successful = isSlotFlagSet(slot, AB_ATTR_SUCCESSFUL); - } - - return successful ? BoolResult::TRUE : BoolResult::FALSE; -} - -Return<void> BootControl::getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) { - _hidl_cb(slot == 0 ? "_a" : slot == 1 ? "_b" : ""); - return Void(); -} - -// Methods from ::android::hardware::boot::V1_1::IBootControl follow. -bool BootControl::Init() { - return InitMiscVirtualAbMessageIfNeeded(); -} - -Return<bool> BootControl::setSnapshotMergeStatus( - ::android::hardware::boot::V1_1::MergeStatus status) { - return SetMiscVirtualAbMergeStatus(getCurrentSlot(), status); -} - -Return<::android::hardware::boot::V1_1::MergeStatus> BootControl::getSnapshotMergeStatus() { - MergeStatus status; - if (!GetMiscVirtualAbMergeStatus(getCurrentSlot(), &status)) { - return MergeStatus::UNKNOWN; - } - return status; -} - -// Methods from ::android::hardware::boot::V1_2::IBootControl follow. -Return<uint32_t> BootControl::getActiveBootSlot() { - if (getNumberSlots() == 0) - return 0; - - if (isDevInfoValid()) - return devinfo.ab_data.slots[1].active ? 1 : 0; - return isSlotFlagSet(1, AB_ATTR_ACTIVE) ? 1 : 0; -} - -// Methods from ::android::hidl::base::V1_0::IBase follow. - -IBootControl *HIDL_FETCH_IBootControl(const char * /* name */) { - auto module = new BootControl(); - - module->Init(); - - return module; -} - -} // namespace implementation -} // namespace V1_2 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.2/BootControl.h b/interfaces/boot/1.2/BootControl.h deleted file mode 100644 index 45b7efa..0000000 --- a/interfaces/boot/1.2/BootControl.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <android/hardware/boot/1.2/IBootControl.h> -#include <hidl/MQDescriptor.h> -#include <hidl/Status.h> - -namespace android { -namespace hardware { -namespace boot { -namespace V1_2 { -namespace implementation { - -using ::android::sp; -using ::android::hardware::hidl_array; -using ::android::hardware::hidl_memory; -using ::android::hardware::hidl_string; -using ::android::hardware::hidl_vec; -using ::android::hardware::Return; -using ::android::hardware::Void; - -struct BootControl : public IBootControl { - bool Init(); - - // Methods from ::android::hardware::boot::V1_0::IBootControl follow. - Return<uint32_t> getNumberSlots() override; - Return<uint32_t> getCurrentSlot() override; - Return<void> markBootSuccessful(markBootSuccessful_cb _hidl_cb) override; - Return<void> setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) override; - Return<void> setSlotAsUnbootable(uint32_t slot, setSlotAsUnbootable_cb _hidl_cb) override; - Return<::android::hardware::boot::V1_0::BoolResult> isSlotBootable(uint32_t slot) override; - Return<::android::hardware::boot::V1_0::BoolResult> isSlotMarkedSuccessful( - uint32_t slot) override; - Return<void> getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) override; - - // Methods from ::android::hardware::boot::V1_1::IBootControl follow. - Return<bool> setSnapshotMergeStatus( - ::android::hardware::boot::V1_1::MergeStatus status) override; - Return<::android::hardware::boot::V1_1::MergeStatus> getSnapshotMergeStatus() override; - - // Methods from ::android::hardware::boot::V1_2::IBootControl follow. - Return<uint32_t> getActiveBootSlot() override; - - // Methods from ::android::hidl::base::V1_0::IBase follow. -}; - -// FIXME: most likely delete, this is only for passthrough implementations -extern "C" IBootControl *HIDL_FETCH_IBootControl(const char *name); - -enum otpmgr_command : uint32_t { - OTP_REQ_SHIFT = 1, - OTP_RESP_BIT = 1, - OTP_CMD_write_antirbk_non_secure_ap = (7 << OTP_REQ_SHIFT), - OTP_CMD_write_antirbk_secure_ap = (8 << OTP_REQ_SHIFT), -}; - -struct otp_mgr_req_base { - uint32_t command; - uint32_t resp_payload_size; - uint8_t handle; -}__packed; - -struct otp_mgr_rsp_base { - uint32_t command; - uint32_t resp_payload_size; - int result; -}__packed; - -} // namespace implementation -} // namespace V1_2 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.2/DevInfo.h b/interfaces/boot/1.2/DevInfo.h deleted file mode 100644 index a09a83a..0000000 --- a/interfaces/boot/1.2/DevInfo.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -namespace android { -namespace hardware { -namespace boot { -namespace V1_2 { -namespace implementation { - -// -// definitions taken from ABL code -// - -constexpr uint32_t DEVINFO_MAGIC = 0x49564544; -constexpr size_t DEVINFO_AB_SLOT_COUNT = 2; - -struct devinfo_ab_slot_data_t { - uint8_t retry_count; - uint8_t unbootable : 1; - uint8_t successful : 1; - uint8_t active : 1; - uint8_t fastboot_ok : 1; - uint8_t : 4; - uint8_t unused[2]; -} __attribute__((packed)); - -typedef struct { - devinfo_ab_slot_data_t slots[DEVINFO_AB_SLOT_COUNT]; -} __attribute__((packed)) devinfo_ab_data_t; - -struct devinfo_t { - uint32_t magic; - uint16_t ver_major; - uint16_t ver_minor; - uint8_t unused[40]; - devinfo_ab_data_t ab_data; - uint8_t unused1[72]; // use remaining up to complete 128 bytes -} __attribute__((packed)); - -static_assert(sizeof(devinfo_t) == 128, "invalid devinfo struct size"); - -} // namespace implementation -} // namespace V1_2 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.2/GptUtils.cpp b/interfaces/boot/1.2/GptUtils.cpp deleted file mode 100644 index 25088e7..0000000 --- a/interfaces/boot/1.2/GptUtils.cpp +++ /dev/null @@ -1,193 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "bootcontrolhal" - -#include "GptUtils.h" - -#include <android-base/file.h> -#include <errno.h> -#include <linux/fs.h> -#include <log/log.h> -#include <zlib.h> - -namespace android { -namespace hardware { -namespace boot { -namespace V1_2 { -namespace implementation { - -namespace { - -static int ValidateGptHeader(gpt_header *gpt) { - if (gpt->signature != GPT_SIGNATURE) { - ALOGE("invalid gpt signature 0x%lx\n", gpt->signature); - return -1; - } - - if (gpt->header_size != sizeof(gpt_header)) { - ALOGE("invalid gpt header size %u\n", gpt->header_size); - return -1; - } - - if (gpt->entry_size != sizeof(gpt_entry)) { - ALOGE("invalid gpt entry size %u\n", gpt->entry_size); - return -1; - } - - return 0; -} - -} // namespace - -GptUtils::GptUtils(const std::string dev_path) : dev_path(dev_path), fd(0) {} - -int GptUtils::Load(void) { - fd = open(dev_path.c_str(), O_RDWR); - if (fd < 0) { - ALOGE("failed to open block dev %s, %d\n", dev_path.c_str(), errno); - return -1; - } - - int ret = ioctl(fd, BLKSSZGET, &block_size); - if (ret < 0) { - ALOGE("failed to get block size %d\n", errno); - return -1; - } - - // read primary header - lseek64(fd, block_size, SEEK_SET); - ret = read(fd, &gpt_primary, sizeof gpt_primary); - if (ret < 0) { - ALOGE("failed to read gpt primary header %d\n", errno); - return -1; - } - - if (ValidateGptHeader(&gpt_primary)) { - ALOGE("error validating gpt header\n"); - return -1; - } - - // read partition entries - entry_array.resize(gpt_primary.entry_count); - uint32_t entries_size = gpt_primary.entry_size * gpt_primary.entry_count; - lseek64(fd, block_size * gpt_primary.start_lba, SEEK_SET); - ret = read(fd, entry_array.data(), entries_size); - if (ret < 0) { - ALOGE("failed to read gpt partition entries %d\n", errno); - return -1; - } - - // read gpt back header - lseek64(fd, block_size * gpt_primary.backup_lba, SEEK_SET); - ret = read(fd, &gpt_backup, sizeof gpt_backup); - if (ret < 0) { - ALOGE("failed to read gpt backup header %d\n", errno); - return -1; - } - - if (ValidateGptHeader(&gpt_backup)) { - ALOGW("error validating gpt backup\n"); // just warn about it, not fail - } - - // Create map <partition name, gpt_entry pointer> - auto get_name = [](const uint16_t *efi_name) { - char name[37] = {}; - for (int i = 0; efi_name[i] && i < sizeof name - 1; ++i) name[i] = efi_name[i]; - return std::string(name); - }; - - for (auto const &e : entry_array) { - if (e.name[0] == 0) - break; // stop at the first partition with no name - std::string s = get_name(e.name); - entries[s] = const_cast<gpt_entry *>(&e); - } - - return 0; -} - -gpt_entry *GptUtils::GetPartitionEntry(std::string name) { - return entries.find(name) != entries.end() ? entries[name] : nullptr; -} - -int GptUtils::Sync(void) { - if (!fd) - return -1; - - // calculate crc and check if we need to update gpt - gpt_primary.entries_crc32 = crc32(0, reinterpret_cast<uint8_t *>(entry_array.data()), - entry_array.size() * sizeof(gpt_entry)); - - // save old crc - uint32_t crc = gpt_primary.crc32; - gpt_primary.crc32 = 0; - - gpt_primary.crc32 = crc32(0, reinterpret_cast<uint8_t *>(&gpt_primary), sizeof gpt_primary); - if (crc == gpt_primary.crc32) - return 0; // nothing to do (no changes) - - ALOGI("updating GPT\n"); - - lseek64(fd, block_size * gpt_primary.current_lba, SEEK_SET); - int ret = write(fd, &gpt_primary, sizeof gpt_primary); - if (ret < 0) { - ALOGE("failed to write gpt primary header %d\n", errno); - return -1; - } - - lseek64(fd, block_size * gpt_primary.start_lba, SEEK_SET); - ret = write(fd, entry_array.data(), entry_array.size() * sizeof(gpt_entry)); - if (ret < 0) { - ALOGE("failed to write gpt partition entries %d\n", errno); - return -1; - } - - // update GPT backup entries and backup - lseek64(fd, block_size * gpt_backup.start_lba, SEEK_SET); - ret = write(fd, entry_array.data(), entry_array.size() * sizeof(gpt_entry)); - if (ret < 0) { - ALOGE("failed to write gpt backup partition entries %d\n", errno); - return -1; - } - - gpt_backup.entries_crc32 = gpt_primary.entries_crc32; - gpt_backup.crc32 = 0; - gpt_backup.crc32 = crc32(0, reinterpret_cast<uint8_t *>(&gpt_backup), sizeof gpt_backup); - lseek64(fd, block_size * gpt_primary.backup_lba, SEEK_SET); - ret = write(fd, &gpt_backup, sizeof gpt_backup); - if (ret < 0) { - ALOGE("failed to write gpt backup header %d\n", errno); - return -1; - } - - fsync(fd); - - return 0; -} - -GptUtils::~GptUtils() { - if (fd) { - Sync(); - close(fd); - } -} - -} // namespace implementation -} // namespace V1_2 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.2/GptUtils.h b/interfaces/boot/1.2/GptUtils.h deleted file mode 100644 index a2bed33..0000000 --- a/interfaces/boot/1.2/GptUtils.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <map> -#include <string> -#include <vector> - -namespace android { -namespace hardware { -namespace boot { -namespace V1_2 { -namespace implementation { - -#define GPT_SIGNATURE 0x5452415020494645UL - -typedef struct { - uint8_t type_guid[16]; - uint8_t guid[16]; - uint64_t first_lba; - uint64_t last_lba; - uint64_t attr; - uint16_t name[36]; -} __attribute__((packed)) gpt_entry; - -typedef struct { - uint64_t signature; - uint32_t revision; - uint32_t header_size; - uint32_t crc32; - uint32_t reserved; - uint64_t current_lba; - uint64_t backup_lba; - uint64_t first_usable_lba; - uint64_t last_usable_lba; - uint8_t disk_guid[16]; - uint64_t start_lba; - uint32_t entry_count; - uint32_t entry_size; - uint32_t entries_crc32; -} __attribute__((packed)) gpt_header; - -class GptUtils { - public: - GptUtils(const std::string dev_path); - int Load(void); - gpt_entry *GetPartitionEntry(std::string name); - int Sync(void); - ~GptUtils(); - - private: - std::string dev_path; - int fd; - uint32_t block_size; - gpt_header gpt_primary; - gpt_header gpt_backup; - std::vector<gpt_entry> entry_array; - std::map<std::string, gpt_entry *> entries; -}; - -} // namespace implementation -} // namespace V1_2 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.2/android.hardware.boot@1.2-service-zuma.rc b/interfaces/boot/1.2/android.hardware.boot@1.2-service-zuma.rc deleted file mode 100644 index 4e5f5fe..0000000 --- a/interfaces/boot/1.2/android.hardware.boot@1.2-service-zuma.rc +++ /dev/null @@ -1,7 +0,0 @@ -service vendor.boot-hal-1-2 /vendor/bin/hw/android.hardware.boot@1.2-service-zuma - interface android.hardware.boot@1.0::IBootControl default - interface android.hardware.boot@1.1::IBootControl default - interface android.hardware.boot@1.2::IBootControl default - class early_hal - user root - group root drmrpc diff --git a/interfaces/boot/1.2/service.cpp b/interfaces/boot/1.2/service.cpp deleted file mode 100644 index f07682e..0000000 --- a/interfaces/boot/1.2/service.cpp +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "android.hardware.boot@1.2-service" - -#include <android/hardware/boot/1.2/IBootControl.h> -#include <hidl/HidlTransportSupport.h> -#include <hidl/Status.h> -#include <log/log.h> - -#include "BootControl.h" - -using ::android::status_t; - -using ::android::hardware::boot::V1_2::IBootControl; - -using ::android::hardware::boot::V1_2::implementation::BootControl; -// using ::android::hardware::boot::implementation::BootControl; - -int main(int /* argc */, char * /* argv */[]) { - // This function must be called before you join to ensure the proper - // number of threads are created. The threadpool will never exceed - // size one because of this call. - ::android::hardware::configureRpcThreadpool(1 /*threads*/, true /*willJoin*/); - - ::android::sp bootctrl = new BootControl(); - const status_t status = bootctrl->registerAsService(); - if (status != ::android::OK) { - return 1; // or handle error - } - - // Adds this thread to the threadpool, resulting in one total - // thread in the threadpool. We could also do other things, but - // would have to specify 'false' to willJoin in configureRpcThreadpool. - ::android::hardware::joinRpcThreadpool(); - return 1; // joinRpcThreadpool should never return -} diff --git a/interfaces/boot/aidl/Android.bp b/interfaces/boot/aidl/Android.bp deleted file mode 100644 index 37d2aeb..0000000 --- a/interfaces/boot/aidl/Android.bp +++ /dev/null @@ -1,65 +0,0 @@ -// -// Copyright (C) 2023 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -package { - // See: http://go/android-license-faq - // A large-scale-change added 'default_applicable_licenses' to import - // all of the 'license_kinds' from "//device/google/zuma:device_google_zuma_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: [ - "//device/google/zuma:device_google_zuma_license", - ], -} - -cc_defaults { - name: "android.hardware.boot-service_common-zuma", - relative_install_path: "hw", - defaults: ["libboot_control_defaults"], - shared_libs: [ - "libbase", - "libbinder_ndk", - "libcutils", - "libz", - "libtrusty", - "android.hardware.boot@1.1", - "android.hardware.boot-V1-ndk", - ], - static_libs: [ - "libboot_control", - "libbootloader_message_vendor", - ], - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - "service.cpp" - ], -} - -cc_binary { - name: "android.hardware.boot-service.default-zuma", - defaults: ["android.hardware.boot-service_common-zuma"], - init_rc: ["android.hardware.boot-service.default-zuma.rc"], - vendor: true, -} - -cc_binary { - name: "android.hardware.boot-service.default_recovery-zuma", - defaults: ["android.hardware.boot-service_common-zuma"], - vintf_fragments: ["android.hardware.boot-service.default_recovery-zuma.xml"], - init_rc: ["android.hardware.boot-service.default_recovery-zuma.rc"], - recovery: true, -}
\ No newline at end of file diff --git a/interfaces/boot/aidl/BootControl.cpp b/interfaces/boot/aidl/BootControl.cpp deleted file mode 100644 index 941b0d2..0000000 --- a/interfaces/boot/aidl/BootControl.cpp +++ /dev/null @@ -1,538 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "bootcontrolhal" - -#include "BootControl.h" - -#include <android-base/file.h> -#include <android-base/logging.h> -#include <android-base/unique_fd.h> -#include <bootloader_message/bootloader_message.h> -#include <cutils/properties.h> -#include <libboot_control/libboot_control.h> -#include <log/log.h> -#include <trusty/tipc.h> - -#include "DevInfo.h" -#include "GptUtils.h" - -using HIDLMergeStatus = ::android::bootable::BootControl::MergeStatus; -using ndk::ScopedAStatus; - -using android::bootable::GetMiscVirtualAbMergeStatus; -using android::bootable::InitMiscVirtualAbMessageIfNeeded; -using android::bootable::SetMiscVirtualAbMergeStatus; - -namespace aidl::android::hardware::boot { - -namespace { - -// clang-format off - -#define BOOT_A_PATH "/dev/block/by-name/boot_a" -#define BOOT_B_PATH "/dev/block/by-name/boot_b" -#define DEVINFO_PATH "/dev/block/by-name/devinfo" - -// slot flags -#define AB_ATTR_PRIORITY_SHIFT 52 -#define AB_ATTR_PRIORITY_MASK (3UL << AB_ATTR_PRIORITY_SHIFT) -#define AB_ATTR_ACTIVE_SHIFT 54 -#define AB_ATTR_ACTIVE (1UL << AB_ATTR_ACTIVE_SHIFT) -#define AB_ATTR_RETRY_COUNT_SHIFT (55) -#define AB_ATTR_RETRY_COUNT_MASK (7UL << AB_ATTR_RETRY_COUNT_SHIFT) -#define AB_ATTR_SUCCESSFUL (1UL << 58) -#define AB_ATTR_UNBOOTABLE (1UL << 59) - -#define AB_ATTR_MAX_PRIORITY 3UL -#define AB_ATTR_MAX_RETRY_COUNT 3UL - -// clang-format on - -static std::string getDevPath(int32_t in_slot) { - char real_path[PATH_MAX]; - - const char *path = in_slot == 0 ? BOOT_A_PATH : BOOT_B_PATH; - - int ret = readlink(path, real_path, sizeof real_path); - if (ret < 0) { - ALOGE("readlink failed for boot device %s\n", strerror(errno)); - return std::string(); - } - - std::string dp(real_path); - // extract /dev/sda.. part - return dp.substr(0, sizeof "/dev/block/sdX" - 1); -} - -static bool isSlotFlagSet(int32_t in_slot, uint64_t flag) { - std::string dev_path = getDevPath(in_slot); - if (dev_path.empty()) { - ALOGI("Could not get device path for slot %d\n", in_slot); - return false; - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - ALOGI("failed to load gpt data\n"); - return false; - } - - gpt_entry *e = gpt.GetPartitionEntry(in_slot ? "boot_b" : "boot_a"); - if (e == nullptr) { - ALOGI("failed to get gpt entry\n"); - return false; - } - - return !!(e->attr & flag); -} - -static bool setSlotFlag(int32_t in_slot, uint64_t flag) { - std::string dev_path = getDevPath(in_slot); - if (dev_path.empty()) { - ALOGI("Could not get device path for slot %d\n", in_slot); - return false; - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - ALOGI("failed to load gpt data\n"); - return false; - } - - gpt_entry *e = gpt.GetPartitionEntry(in_slot ? "boot_b" : "boot_a"); - if (e == nullptr) { - ALOGI("failed to get gpt entry\n"); - return false; - } - - e->attr |= flag; - gpt.Sync(); - - return true; -} - -static bool is_devinfo_valid; -static bool is_devinfo_initialized; -static std::mutex devinfo_lock; -static devinfo_t devinfo; - -static bool isDevInfoValid() { - const std::lock_guard<std::mutex> lock(devinfo_lock); - - if (is_devinfo_initialized) { - return is_devinfo_valid; - } - - is_devinfo_initialized = true; - - ::android::base::unique_fd fd(open(DEVINFO_PATH, O_RDONLY)); - ::android::base::ReadFully(fd, &devinfo, sizeof devinfo); - - if (devinfo.magic != DEVINFO_MAGIC) { - return is_devinfo_valid; - } - - uint32_t version = ((uint32_t)devinfo.ver_major << 16) | devinfo.ver_minor; - // only version 3.3+ supports A/B data - if (version >= 0x0003'0003) { - is_devinfo_valid = true; - } - - return is_devinfo_valid; -} - -static bool DevInfoSync() { - if (!isDevInfoValid()) { - return false; - } - - ::android::base::unique_fd fd(open(DEVINFO_PATH, O_WRONLY | O_DSYNC)); - return ::android::base::WriteFully(fd, &devinfo, sizeof devinfo); -} - -static void DevInfoInitSlot(devinfo_ab_slot_data_t &slot_data) { - slot_data.retry_count = AB_ATTR_MAX_RETRY_COUNT; - slot_data.unbootable = 0; - slot_data.successful = 0; - slot_data.active = 1; - slot_data.fastboot_ok = 0; -} - -static int blow_otp_AR(bool secure) { - static const char *dev_name = "/dev/trusty-ipc-dev0"; - static const char *otp_name = "com.android.trusty.otp_manager.tidl"; - int fd = 1, ret = 0; - uint32_t cmd = secure? OTP_CMD_write_antirbk_secure_ap : OTP_CMD_write_antirbk_non_secure_ap; - fd = tipc_connect(dev_name, otp_name); - if (fd < 0) { - ALOGI("Failed to connect to OTP_MGR ns TA - is it missing?\n"); - ret = -1; - return ret; - } - - struct otp_mgr_req_base req = { - .command = cmd, - .resp_payload_size = 0, - }; - struct iovec iov[] = { - { - .iov_base = &req, - .iov_len = sizeof(req), - }, - }; - - size_t rc = tipc_send(fd, iov, 1, NULL, 0); - if (rc != sizeof(req)) { - ALOGI("Send fail! %zx\n", rc); - return rc; - } - - struct otp_mgr_rsp_base resp; - rc = read(fd, &resp, sizeof(resp)); - if (rc < 0) { - ALOGI("Read fail! %zx\n", rc); - return rc; - } - - if (rc < sizeof(resp)) { - ALOGI("Not enough data! %zx\n", rc); - return -EIO; - } - - if (resp.command != (cmd | OTP_RESP_BIT)) { - ALOGI("Wrong command! %x\n", resp.command); - return -EINVAL; - } - - if (resp.result != 0) { - fprintf(stderr, "AR writing error! %x\n", resp.result); - return -EINVAL; - } - - tipc_close(fd); - return 0; -} - -static bool blowAR() { - int ret = blow_otp_AR(true); - if (ret) { - ALOGI("Blow secure anti-rollback OTP failed"); - return false; - } - - ret = blow_otp_AR(false); - if (ret) { - ALOGI("Blow non-secure anti-rollback OTP failed"); - return false; - } - - return true; -} - -static constexpr MergeStatus ToAIDLMergeStatus(HIDLMergeStatus status) { - switch (status) { - case HIDLMergeStatus::NONE: - return MergeStatus::NONE; - case HIDLMergeStatus::UNKNOWN: - return MergeStatus::UNKNOWN; - case HIDLMergeStatus::SNAPSHOTTED: - return MergeStatus::SNAPSHOTTED; - case HIDLMergeStatus::MERGING: - return MergeStatus::MERGING; - case HIDLMergeStatus::CANCELLED: - return MergeStatus::CANCELLED; - } -} - -static constexpr HIDLMergeStatus ToHIDLMergeStatus(MergeStatus status) { - switch (status) { - case MergeStatus::NONE: - return HIDLMergeStatus::NONE; - case MergeStatus::UNKNOWN: - return HIDLMergeStatus::UNKNOWN; - case MergeStatus::SNAPSHOTTED: - return HIDLMergeStatus::SNAPSHOTTED; - case MergeStatus::MERGING: - return HIDLMergeStatus::MERGING; - case MergeStatus::CANCELLED: - return HIDLMergeStatus::CANCELLED; - } -} - -} // namespace - -BootControl::BootControl() { - CHECK(InitMiscVirtualAbMessageIfNeeded()); -} - -ScopedAStatus BootControl::getActiveBootSlot(int32_t* _aidl_return) { - int32_t slots = 0; - getNumberSlots(&slots); - if (slots == 0) { - *_aidl_return = 0; - return ScopedAStatus::ok(); - } - - if (isDevInfoValid()) { - *_aidl_return = devinfo.ab_data.slots[1].active ? 1 : 0; - return ScopedAStatus::ok(); - } - *_aidl_return = isSlotFlagSet(1, AB_ATTR_ACTIVE) ? 1 : 0; - return ScopedAStatus::ok(); -} - -ScopedAStatus BootControl::getCurrentSlot(int32_t* _aidl_return) { - char suffix[PROPERTY_VALUE_MAX]; - property_get("ro.boot.slot_suffix", suffix, "_a"); - *_aidl_return = std::string(suffix) == "_b" ? 1 : 0; - return ScopedAStatus::ok(); -} - -ScopedAStatus BootControl::getNumberSlots(int32_t* _aidl_return) { - int32_t slots = 0; - - if (access(BOOT_A_PATH, F_OK) == 0) - slots++; - - if (access(BOOT_B_PATH, F_OK) == 0) - slots++; - - *_aidl_return = slots; - return ScopedAStatus::ok(); -} - -ScopedAStatus BootControl::getSnapshotMergeStatus(MergeStatus* _aidl_return) { - HIDLMergeStatus status; - int32_t current_slot = 0; - getCurrentSlot(¤t_slot); - if (!GetMiscVirtualAbMergeStatus(current_slot, &status)) { - *_aidl_return = MergeStatus::UNKNOWN; - return ScopedAStatus::ok(); - } - *_aidl_return = ToAIDLMergeStatus(status); - return ScopedAStatus::ok(); -} - -ScopedAStatus BootControl::getSuffix(int32_t in_slot, std::string* _aidl_return) { - *_aidl_return = in_slot == 0 ? "_a" : in_slot == 1 ? "_b" : ""; - return ScopedAStatus::ok(); -} - -ScopedAStatus BootControl::isSlotBootable(int32_t in_slot, bool* _aidl_return) { - int32_t slots = 0; - getNumberSlots(&slots); - if (slots == 0) { - *_aidl_return = false; - return ScopedAStatus::ok(); - } - if (in_slot >= slots) - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str()); - - bool unbootable; - if (isDevInfoValid()) { - auto &slot_data = devinfo.ab_data.slots[in_slot]; - unbootable = !!slot_data.unbootable; - } else { - unbootable = isSlotFlagSet(in_slot, AB_ATTR_UNBOOTABLE); - } - - *_aidl_return = unbootable ? false: true; - return ScopedAStatus::ok(); -} - -ScopedAStatus BootControl::isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) { - int32_t slots = 0; - getNumberSlots(&slots); - if (slots == 0) { - // just return true so that we don't we another call trying to mark it as successful - // when there is no slots - *_aidl_return = true; - return ScopedAStatus::ok(); - } - if (in_slot >= slots) - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str()); - - bool successful; - if (isDevInfoValid()) { - auto &slot_data = devinfo.ab_data.slots[in_slot]; - successful = !!slot_data.successful; - } else { - successful = isSlotFlagSet(in_slot, AB_ATTR_SUCCESSFUL); - } - - *_aidl_return = successful ? true : false; - return ScopedAStatus::ok(); -} - -ScopedAStatus BootControl::markBootSuccessful() { - int32_t slots = 0; - getNumberSlots(&slots); - if (slots == 0) { - // no slots, just return true otherwise Android keeps trying - return ScopedAStatus::ok(); - } - - bool ret; - int32_t current_slot = 0; - getCurrentSlot(¤t_slot); - if (isDevInfoValid()) { - auto const slot = current_slot; - devinfo.ab_data.slots[slot].successful = 1; - ret = DevInfoSync(); - } else { - ret = setSlotFlag(current_slot, AB_ATTR_SUCCESSFUL); - } - - if (!ret) { - return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED, - "Failed to set successful flag"); - } - - if (!blowAR()) { - ALOGE("Failed to blow anti-rollback counter"); - // Ignore the error, since ABL will re-trigger it on reboot - } - - return ScopedAStatus::ok(); -} - -ScopedAStatus BootControl::setActiveBootSlot(int32_t in_slot) { - if (in_slot >= 2) { - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str()); - } - - if (isDevInfoValid()) { - auto &active_slot_data = devinfo.ab_data.slots[in_slot]; - auto &inactive_slot_data = devinfo.ab_data.slots[!in_slot]; - - inactive_slot_data.active = 0; - DevInfoInitSlot(active_slot_data); - - if (!DevInfoSync()) { - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - COMMAND_FAILED, "Could not update DevInfo data"); - } - } else { - std::string dev_path = getDevPath(in_slot); - if (dev_path.empty()) { - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - COMMAND_FAILED, "Could not get device path for slot"); - } - - GptUtils gpt(dev_path); - if (gpt.Load()) { - return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED, - "failed to load gpt data"); - } - - gpt_entry *active_entry = gpt.GetPartitionEntry(in_slot == 0 ? "boot_a" : "boot_b"); - gpt_entry *inactive_entry = gpt.GetPartitionEntry(in_slot == 0 ? "boot_b" : "boot_a"); - if (active_entry == nullptr || inactive_entry == nullptr) { - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - COMMAND_FAILED, "failed to get entries for boot partitions"); - } - - ALOGV("slot active attributes %lx\n", active_entry->attr); - ALOGV("slot inactive attributes %lx\n", inactive_entry->attr); - - // update attributes for active and inactive - inactive_entry->attr &= ~AB_ATTR_ACTIVE; - active_entry->attr = AB_ATTR_ACTIVE | (AB_ATTR_MAX_PRIORITY << AB_ATTR_PRIORITY_SHIFT) | - (AB_ATTR_MAX_RETRY_COUNT << AB_ATTR_RETRY_COUNT_SHIFT); - } - - char boot_dev[PROPERTY_VALUE_MAX]; - property_get("ro.boot.bootdevice", boot_dev, ""); - if (boot_dev[0] == '\0') { - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - COMMAND_FAILED, "invalid ro.boot.bootdevice prop"); - } - - std::string boot_lun_path = - std::string("/sys/devices/platform/") + boot_dev + "/pixel/boot_lun_enabled"; - int fd = open(boot_lun_path.c_str(), O_RDWR | O_DSYNC); - if (fd < 0) { - // Try old path for kernels < 5.4 - // TODO: remove once kernel 4.19 support is deprecated - std::string boot_lun_path = - std::string("/sys/devices/platform/") + boot_dev + "/attributes/boot_lun_enabled"; - fd = open(boot_lun_path.c_str(), O_RDWR | O_DSYNC); - if (fd < 0) { - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - COMMAND_FAILED, "failed to open ufs attr boot_lun_enabled"); - } - } - - // - // bBootLunEn - // 0x1 => Boot LU A = enabled, Boot LU B = disable - // 0x2 => Boot LU A = disable, Boot LU B = enabled - // - int ret = ::android::base::WriteStringToFd(in_slot == 0 ? "1" : "2", fd); - close(fd); - if (ret < 0) { - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - COMMAND_FAILED, "faied to write boot_lun_enabled attribute"); - } - - return ScopedAStatus::ok(); -} - -ScopedAStatus BootControl::setSlotAsUnbootable(int32_t in_slot) { - if (in_slot >= 2) - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - INVALID_SLOT, (std::string("Invalid slot ") + std::to_string(in_slot)).c_str()); - - if (isDevInfoValid()) { - auto &slot_data = devinfo.ab_data.slots[in_slot]; - slot_data.unbootable = 1; - if (!DevInfoSync()) { - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - COMMAND_FAILED, "Could not update DevInfo data"); - } - } else { - std::string dev_path = getDevPath(in_slot); - if (dev_path.empty()) { - return ScopedAStatus::fromServiceSpecificErrorWithMessage( - COMMAND_FAILED, "Could not get device path for slot"); - } - - GptUtils gpt(dev_path); - gpt.Load(); - - gpt_entry *e = gpt.GetPartitionEntry(in_slot ? "boot_b" : "boot_a"); - e->attr |= AB_ATTR_UNBOOTABLE; - - gpt.Sync(); - } - - return ScopedAStatus::ok(); -} - -ScopedAStatus BootControl::setSnapshotMergeStatus(MergeStatus in_status) { - int32_t current_slot = 0; - getCurrentSlot(¤t_slot); - if (!SetMiscVirtualAbMergeStatus(current_slot, ToHIDLMergeStatus(in_status))) - return ScopedAStatus::fromServiceSpecificErrorWithMessage(COMMAND_FAILED, - "Operation failed"); - return ScopedAStatus::ok(); -} - -} // namespace aidl::android::hardware::boot diff --git a/interfaces/boot/aidl/BootControl.h b/interfaces/boot/aidl/BootControl.h deleted file mode 100644 index a54f66d..0000000 --- a/interfaces/boot/aidl/BootControl.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <aidl/android/hardware/boot/BnBootControl.h> -#include <libboot_control/libboot_control.h> - -namespace aidl::android::hardware::boot { - -class BootControl final : public BnBootControl { - public: - BootControl(); - ::ndk::ScopedAStatus getActiveBootSlot(int32_t* _aidl_return) override; - ::ndk::ScopedAStatus getCurrentSlot(int32_t* _aidl_return) override; - ::ndk::ScopedAStatus getNumberSlots(int32_t* _aidl_return) override; - ::ndk::ScopedAStatus getSnapshotMergeStatus( - ::aidl::android::hardware::boot::MergeStatus* _aidl_return) override; - ::ndk::ScopedAStatus getSuffix(int32_t in_slot, std::string* _aidl_return) override; - ::ndk::ScopedAStatus isSlotBootable(int32_t in_slot, bool* _aidl_return) override; - ::ndk::ScopedAStatus isSlotMarkedSuccessful(int32_t in_slot, bool* _aidl_return) override; - ::ndk::ScopedAStatus markBootSuccessful() override; - ::ndk::ScopedAStatus setActiveBootSlot(int32_t in_slot) override; - ::ndk::ScopedAStatus setSlotAsUnbootable(int32_t in_slot) override; - ::ndk::ScopedAStatus setSnapshotMergeStatus( - ::aidl::android::hardware::boot::MergeStatus in_status) override; -}; - -enum otpmgr_command : uint32_t { - OTP_REQ_SHIFT = 1, - OTP_RESP_BIT = 1, - OTP_CMD_write_antirbk_non_secure_ap = (7 << OTP_REQ_SHIFT), - OTP_CMD_write_antirbk_secure_ap = (8 << OTP_REQ_SHIFT), -}; - -struct otp_mgr_req_base { - uint32_t command; - uint32_t resp_payload_size; - uint8_t handle; -}__packed; - -struct otp_mgr_rsp_base { - uint32_t command; - uint32_t resp_payload_size; - int result; -}__packed; - -} // namespace aidl::android::hardware::boot
\ No newline at end of file diff --git a/interfaces/boot/aidl/DevInfo.h b/interfaces/boot/aidl/DevInfo.h deleted file mode 100644 index aa5f5d3..0000000 --- a/interfaces/boot/aidl/DevInfo.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2021 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -namespace aidl::android::hardware::boot { - -// -// definitions taken from ABL code -// - -constexpr uint32_t DEVINFO_MAGIC = 0x49564544; -constexpr size_t DEVINFO_AB_SLOT_COUNT = 2; - -struct devinfo_ab_slot_data_t { - uint8_t retry_count; - uint8_t unbootable : 1; - uint8_t successful : 1; - uint8_t active : 1; - uint8_t fastboot_ok : 1; - uint8_t : 4; - uint8_t unused[2]; -} __attribute__((packed)); - -typedef struct { - devinfo_ab_slot_data_t slots[DEVINFO_AB_SLOT_COUNT]; -} __attribute__((packed)) devinfo_ab_data_t; - -struct devinfo_t { - uint32_t magic; - uint16_t ver_major; - uint16_t ver_minor; - uint8_t unused[40]; - devinfo_ab_data_t ab_data; - uint8_t unused1[72]; // use remaining up to complete 128 bytes -} __attribute__((packed)); - -static_assert(sizeof(devinfo_t) == 128, "invalid devinfo struct size"); - -} // namespace aidl::android::hardware::boot
\ No newline at end of file diff --git a/interfaces/boot/aidl/GptUtils.cpp b/interfaces/boot/aidl/GptUtils.cpp deleted file mode 100644 index 34dec11..0000000 --- a/interfaces/boot/aidl/GptUtils.cpp +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "bootcontrolhal" - -#include "GptUtils.h" - -#include <android-base/file.h> -#include <errno.h> -#include <linux/fs.h> -#include <log/log.h> -#include <zlib.h> - -namespace aidl::android::hardware::boot { - -namespace { - -static int ValidateGptHeader(gpt_header *gpt) { - if (gpt->signature != GPT_SIGNATURE) { - ALOGE("invalid gpt signature 0x%lx\n", gpt->signature); - return -1; - } - - if (gpt->header_size != sizeof(gpt_header)) { - ALOGE("invalid gpt header size %u\n", gpt->header_size); - return -1; - } - - if (gpt->entry_size != sizeof(gpt_entry)) { - ALOGE("invalid gpt entry size %u\n", gpt->entry_size); - return -1; - } - - return 0; -} - -} // namespace - -GptUtils::GptUtils(const std::string dev_path) : dev_path(dev_path), fd(0) {} - -int GptUtils::Load(void) { - fd = open(dev_path.c_str(), O_RDWR); - if (fd < 0) { - ALOGE("failed to open block dev %s, %d\n", dev_path.c_str(), errno); - return -1; - } - - int ret = ioctl(fd, BLKSSZGET, &block_size); - if (ret < 0) { - ALOGE("failed to get block size %d\n", errno); - return -1; - } - - // read primary header - lseek64(fd, block_size, SEEK_SET); - ret = read(fd, &gpt_primary, sizeof gpt_primary); - if (ret < 0) { - ALOGE("failed to read gpt primary header %d\n", errno); - return -1; - } - - if (ValidateGptHeader(&gpt_primary)) { - ALOGE("error validating gpt header\n"); - return -1; - } - - // read partition entries - entry_array.resize(gpt_primary.entry_count); - uint32_t entries_size = gpt_primary.entry_size * gpt_primary.entry_count; - lseek64(fd, block_size * gpt_primary.start_lba, SEEK_SET); - ret = read(fd, entry_array.data(), entries_size); - if (ret < 0) { - ALOGE("failed to read gpt partition entries %d\n", errno); - return -1; - } - - // read gpt back header - lseek64(fd, block_size * gpt_primary.backup_lba, SEEK_SET); - ret = read(fd, &gpt_backup, sizeof gpt_backup); - if (ret < 0) { - ALOGE("failed to read gpt backup header %d\n", errno); - return -1; - } - - if (ValidateGptHeader(&gpt_backup)) { - ALOGW("error validating gpt backup\n"); // just warn about it, not fail - } - - // Create map <partition name, gpt_entry pointer> - auto get_name = [](const uint16_t *efi_name) { - char name[37] = {}; - for (size_t i = 0; efi_name[i] && i < sizeof name - 1; ++i) name[i] = efi_name[i]; - return std::string(name); - }; - - for (auto const &e : entry_array) { - if (e.name[0] == 0) - break; // stop at the first partition with no name - std::string s = get_name(e.name); - entries[s] = const_cast<gpt_entry *>(&e); - } - - return 0; -} - -gpt_entry *GptUtils::GetPartitionEntry(std::string name) { - return entries.find(name) != entries.end() ? entries[name] : nullptr; -} - -int GptUtils::Sync(void) { - if (!fd) - return -1; - - // calculate crc and check if we need to update gpt - gpt_primary.entries_crc32 = crc32(0, reinterpret_cast<uint8_t *>(entry_array.data()), - entry_array.size() * sizeof(gpt_entry)); - - // save old crc - uint32_t crc = gpt_primary.crc32; - gpt_primary.crc32 = 0; - - gpt_primary.crc32 = crc32(0, reinterpret_cast<uint8_t *>(&gpt_primary), sizeof gpt_primary); - if (crc == gpt_primary.crc32) - return 0; // nothing to do (no changes) - - ALOGI("updating GPT\n"); - - lseek64(fd, block_size * gpt_primary.current_lba, SEEK_SET); - int ret = write(fd, &gpt_primary, sizeof gpt_primary); - if (ret < 0) { - ALOGE("failed to write gpt primary header %d\n", errno); - return -1; - } - - lseek64(fd, block_size * gpt_primary.start_lba, SEEK_SET); - ret = write(fd, entry_array.data(), entry_array.size() * sizeof(gpt_entry)); - if (ret < 0) { - ALOGE("failed to write gpt partition entries %d\n", errno); - return -1; - } - - // update GPT backup entries and backup - lseek64(fd, block_size * gpt_backup.start_lba, SEEK_SET); - ret = write(fd, entry_array.data(), entry_array.size() * sizeof(gpt_entry)); - if (ret < 0) { - ALOGE("failed to write gpt backup partition entries %d\n", errno); - return -1; - } - - gpt_backup.entries_crc32 = gpt_primary.entries_crc32; - gpt_backup.crc32 = 0; - gpt_backup.crc32 = crc32(0, reinterpret_cast<uint8_t *>(&gpt_backup), sizeof gpt_backup); - lseek64(fd, block_size * gpt_primary.backup_lba, SEEK_SET); - ret = write(fd, &gpt_backup, sizeof gpt_backup); - if (ret < 0) { - ALOGE("failed to write gpt backup header %d\n", errno); - return -1; - } - - fsync(fd); - - return 0; -} - -GptUtils::~GptUtils() { - if (fd) { - Sync(); - close(fd); - } -} - -} // namespace aidl::android::hardware::boot
\ No newline at end of file diff --git a/interfaces/boot/aidl/GptUtils.h b/interfaces/boot/aidl/GptUtils.h deleted file mode 100644 index ec68cf6..0000000 --- a/interfaces/boot/aidl/GptUtils.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <map> -#include <string> -#include <vector> - -namespace aidl::android::hardware::boot { - -#define GPT_SIGNATURE 0x5452415020494645UL - -typedef struct { - uint8_t type_guid[16]; - uint8_t guid[16]; - uint64_t first_lba; - uint64_t last_lba; - uint64_t attr; - uint16_t name[36]; -} __attribute__((packed)) gpt_entry; - -typedef struct { - uint64_t signature; - uint32_t revision; - uint32_t header_size; - uint32_t crc32; - uint32_t reserved; - uint64_t current_lba; - uint64_t backup_lba; - uint64_t first_usable_lba; - uint64_t last_usable_lba; - uint8_t disk_guid[16]; - uint64_t start_lba; - uint32_t entry_count; - uint32_t entry_size; - uint32_t entries_crc32; -} __attribute__((packed)) gpt_header; - -class GptUtils { - public: - GptUtils(const std::string dev_path); - int Load(void); - gpt_entry *GetPartitionEntry(std::string name); - int Sync(void); - ~GptUtils(); - - private: - std::string dev_path; - int fd; - uint32_t block_size; - gpt_header gpt_primary; - gpt_header gpt_backup; - std::vector<gpt_entry> entry_array; - std::map<std::string, gpt_entry *> entries; -}; - -} // namespace aidl::android::hardware::boot
\ No newline at end of file diff --git a/interfaces/boot/aidl/android.hardware.boot-service.default-zuma.rc b/interfaces/boot/aidl/android.hardware.boot-service.default-zuma.rc deleted file mode 100644 index f7dccad..0000000 --- a/interfaces/boot/aidl/android.hardware.boot-service.default-zuma.rc +++ /dev/null @@ -1,5 +0,0 @@ -service vendor.boot-default /vendor/bin/hw/android.hardware.boot-service.default-zuma - class early_hal - user root - group root drmrpc - diff --git a/interfaces/boot/aidl/android.hardware.boot-service.default_recovery-zuma.rc b/interfaces/boot/aidl/android.hardware.boot-service.default_recovery-zuma.rc deleted file mode 100644 index d867a5f..0000000 --- a/interfaces/boot/aidl/android.hardware.boot-service.default_recovery-zuma.rc +++ /dev/null @@ -1,7 +0,0 @@ -service vendor.boot-default /system/bin/hw/android.hardware.boot-service.default_recovery-zuma - class early_hal - user root - group root - seclabel u:r:hal_bootctl_default:s0 - interface aidl android.hardware.boot.IBootControl/default - diff --git a/interfaces/boot/aidl/android.hardware.boot-service.default_recovery-zuma.xml b/interfaces/boot/aidl/android.hardware.boot-service.default_recovery-zuma.xml deleted file mode 100644 index 23ccc4e..0000000 --- a/interfaces/boot/aidl/android.hardware.boot-service.default_recovery-zuma.xml +++ /dev/null @@ -1,6 +0,0 @@ -<manifest version="1.0" type="device"> - <hal format="aidl"> - <name>android.hardware.boot</name> - <fqname>IBootControl/default</fqname> - </hal> -</manifest> diff --git a/interfaces/boot/aidl/service.cpp b/interfaces/boot/aidl/service.cpp deleted file mode 100644 index 41b6c25..0000000 --- a/interfaces/boot/aidl/service.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "aidl.android.hardware.boot-service.default" - -#include <android-base/logging.h> -#include <android/binder_manager.h> -#include <android/binder_process.h> -#include <hidl/HidlSupport.h> -#include <hidl/HidlTransportSupport.h> - -#include "BootControl.h" - -using aidl::android::hardware::boot::BootControl; -using aidl::android::hardware::boot::IBootControl; -using ::android::hardware::configureRpcThreadpool; -using ::android::hardware::joinRpcThreadpool; - -int main(int, char* argv[]) { - android::base::InitLogging(argv, android::base::KernelLogger); - ABinderProcess_setThreadPoolMaxThreadCount(0); - std::shared_ptr<IBootControl> service = ndk::SharedRefBase::make<BootControl>(); - - const std::string instance = std::string(BootControl::descriptor) + "/default"; - auto status = AServiceManager_addService(service->asBinder().get(), instance.c_str()); - CHECK_EQ(status, STATUS_OK) << "Failed to add service " << instance << " " << status; - LOG(INFO) << "IBootControl AIDL service running..."; - - ABinderProcess_joinThreadPool(); - return EXIT_FAILURE; // should not reach -} diff --git a/usb/usb/Android.bp b/usb/usb/Android.bp index 858fc47..a67e617 100644 --- a/usb/usb/Android.bp +++ b/usb/usb/Android.bp @@ -34,7 +34,6 @@ cc_binary { srcs: [ "service.cpp", "Usb.cpp", - "UsbDataSessionMonitor.cpp", ], shared_libs: [ "libbase", diff --git a/usb/usb/Usb.cpp b/usb/usb/Usb.cpp index c0813d9..e63fa1d 100644 --- a/usb/usb/Usb.cpp +++ b/usb/usb/Usb.cpp @@ -27,6 +27,7 @@ #include <stdio.h> #include <sys/types.h> #include <unistd.h> +#include <chrono> #include <regex> #include <thread> #include <unordered_map> @@ -42,6 +43,7 @@ #include <aidl/android/frameworks/stats/IStats.h> #include <android_hardware_usb_flags.h> +#include <pixelusb/CommonUtils.h> #include <pixelusb/UsbGadgetAidlCommon.h> #include <pixelstats/StatsHelper.h> @@ -56,6 +58,9 @@ using android::base::Trim; using android::hardware::google::pixel::getStatsService; using android::hardware::google::pixel::PixelAtoms::VendorUsbPortOverheat; using android::hardware::google::pixel::reportUsbPortOverheat; +using android::hardware::google::pixel::PixelAtoms::VendorUsbDataSessionEvent; +using android::hardware::google::pixel::reportUsbDataSessionEvent; +using android::hardware::google::pixel::usb::BuildVendorUsbDataSessionEvent; namespace aidl { namespace android { @@ -93,22 +98,18 @@ constexpr char kPogoUsbActive[] = "/sys/devices/platform/google,pogo/pogo_usb_ac constexpr char kPogoEnableUsb[] = "/sys/devices/platform/google,pogo/enable_usb"; constexpr char kPowerSupplyUsbType[] = "/sys/class/power_supply/usb/usb_type"; constexpr char kIrqHpdCounPath[] = "-0025/irq_hpd_count"; -constexpr char kUdcUeventRegex[] = - "/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3"; -constexpr char kUdcStatePath[] = - "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state"; -constexpr char kHost1UeventRegex[] = - "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb1/1-0:1.0"; -constexpr char kHost1StatePath[] = "/sys/bus/usb/devices/usb1/1-0:1.0/usb1-port1/state"; -constexpr char kHost2UeventRegex[] = - "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb2/2-0:1.0"; -constexpr char kHost2StatePath[] = "/sys/bus/usb/devices/usb2/2-0:1.0/usb2-port1/state"; -constexpr char kDataRolePath[] = "/sys/devices/platform/11210000.usb/new_data_role"; +constexpr char kUdcState[] = "/sys/devices/platform/11210000.usb/11210000.dwc3/udc/11210000.dwc3/state"; +// xhci-hcd-exynos and usb device numbering could vary on different platforms +constexpr char kHostUeventRegex[] = "^(bind|unbind)@(/devices/platform/11210000\\.usb/11210000\\.dwc3/xhci-hcd-exynos\\.[0-9]\\.auto/)usb([0-9])/[0-9]-0:1\\.0"; constexpr int kSamplingIntervalSec = 5; void queryVersionHelper(android::hardware::usb::Usb *usb, std::vector<PortStatus> *currentPortStatus); AltModeData::DisplayPortAltModeData constructAltModeData(string hpd, string pin_assignment, string link_status, string vdo); +void queryUsbDataSession(android::hardware::usb::Usb *usb, + std::vector<PortStatus> *currentPortStatus); + +#define USB_STATE_MAX_LEN 20 ScopedAStatus Usb::enableUsbData(const string& in_portName, bool in_enable, int64_t in_transactionId) { @@ -510,20 +511,11 @@ bool switchMode(const string &portName, const PortRole &in_role, struct Usb *usb return roleSwitch; } -void updatePortStatus(android::hardware::usb::Usb *usb) { - std::vector<PortStatus> currentPortStatus; - - queryVersionHelper(usb, ¤tPortStatus); -} - Usb::Usb() : mLock(PTHREAD_MUTEX_INITIALIZER), mRoleSwitchLock(PTHREAD_MUTEX_INITIALIZER), mPartnerLock(PTHREAD_MUTEX_INITIALIZER), mPartnerUp(false), - mUsbDataSessionMonitor(kUdcUeventRegex, kUdcStatePath, kHost1UeventRegex, kHost1StatePath, - kHost2UeventRegex, kHost2StatePath, kDataRolePath, - std::bind(&updatePortStatus, this)), mOverheat(ZoneInfo(TemperatureType::USB_PORT, kThermalZoneForTrip, ThrottlingSeverity::CRITICAL), {ZoneInfo(TemperatureType::UNKNOWN, kThermalZoneForTempReadPrimary, @@ -1061,18 +1053,6 @@ Status queryDisplayPortStatus(android::hardware::usb::Usb *usb, return Status::SUCCESS; } -void queryUsbDataSession(android::hardware::usb::Usb *usb, - std::vector<PortStatus> *currentPortStatus) { - std::vector<ComplianceWarning> warnings; - - usb->mUsbDataSessionMonitor.getComplianceWarnings( - (*currentPortStatus)[0].currentDataRole, &warnings); - (*currentPortStatus)[0].complianceWarnings.insert( - (*currentPortStatus)[0].complianceWarnings.end(), - warnings.begin(), - warnings.end()); -} - void queryVersionHelper(android::hardware::usb::Usb *usb, std::vector<PortStatus> *currentPortStatus) { Status status; @@ -1179,6 +1159,54 @@ void report_overheat_event(android::hardware::usb::Usb *usb) { } } +void report_usb_data_session_event(android::hardware::usb::Usb *usb) { + std::vector<VendorUsbDataSessionEvent> events; + + if (usb->mDataRole == PortDataRole::DEVICE) { + VendorUsbDataSessionEvent event; + BuildVendorUsbDataSessionEvent(false /* is_host */, std::chrono::steady_clock::now(), + usb->mDataSessionStart, &usb->mDeviceState.states, + &usb->mDeviceState.timestamps, &event); + events.push_back(event); + } else if (usb->mDataRole == PortDataRole::HOST) { + bool empty = true; + for (auto &entry : usb->mHostStateMap) { + // Host port will at least get an not_attached event after enablement, + // skip upload if no additional state is added. + if (entry.second.states.size() > 1) { + VendorUsbDataSessionEvent event; + BuildVendorUsbDataSessionEvent(true /* is_host */, std::chrono::steady_clock::now(), + usb->mDataSessionStart, &entry.second.states, + &entry.second.timestamps, &event); + events.push_back(event); + empty = false; + } + } + // All host ports have no state update, upload an event to reflect it + if (empty && usb->mHostStateMap.size() > 0) { + VendorUsbDataSessionEvent event; + BuildVendorUsbDataSessionEvent(true /* is_host */, std::chrono::steady_clock::now(), + usb->mDataSessionStart, + &usb->mHostStateMap.begin()->second.states, + &usb->mHostStateMap.begin()->second.timestamps, + &event); + events.push_back(event); + } + } else { + return; + } + + const shared_ptr<IStats> stats_client = getStatsService(); + if (!stats_client) { + ALOGE("Unable to get AIDL Stats service"); + return; + } + + for (auto &event : events) { + reportUsbDataSessionEvent(stats_client, event); + } +} + struct data { int uevent_fd; ::aidl::android::hardware::usb::Usb *usb; @@ -1195,13 +1223,147 @@ enum UeventType matchUeventType(char* str) { return UeventType::UNKNOWN; } -static void uevent_event(uint32_t /*epevents*/, struct data *payload) { +static void unregisterEpollEntry(Usb *usb, std::string name) { + std::map<std::string, struct Usb::epollEntry> *map; + int fd; + + map = &usb->mEpollEntries; + auto it = map->find(name); + if (it != map->end()) { + ALOGI("epoll unregister %s", name.c_str()); + fd = it->second.payload.fd; + epoll_ctl(usb->mEpollFd, EPOLL_CTL_DEL, fd, NULL); + close(fd); + map->erase(it); + } +} + +static void unregisterEpollEntries(Usb *usb) { + std::map<std::string, struct Usb::epollEntry> *map; + std::string name; + + map = &usb->mEpollEntries; + for (auto it = map->begin(); it != map->end();) { + name = it->first; + it++; + unregisterEpollEntry(usb, name); + } +} + +static int registerEpollEntry(Usb *usb, std::string name, int fd, int flags, + void (*func)(uint32_t, struct Usb::payload*)) { + std::map<std::string, struct Usb::epollEntry> *map; + struct Usb::epollEntry *entry; + struct epoll_event ev; + + map = &usb->mEpollEntries; + if (map->find(name) != map->end()) { + ALOGE("%s already registered", name.c_str()); + unregisterEpollEntry(usb, name); + } + + entry = &(*map)[name]; + entry->payload.fd = fd; + entry->payload.name = name; + entry->payload.usb = usb; + entry->cb = std::bind(func, std::placeholders::_1, &entry->payload); + + ev.events = flags; + ev.data.ptr = (void *)&entry->cb; + + if (epoll_ctl(usb->mEpollFd, EPOLL_CTL_ADD, fd, &ev) != 0) { + ALOGE("epoll_ctl failed; errno=%d", errno); + unregisterEpollEntry(usb, name); + return -1; + } + + ALOGI("epoll register %s", name.c_str()); + + return 0; +} + +static int registerEpollEntryByFile(Usb *usb, std::string name, int flags, + void (*func)(uint32_t, struct Usb::payload*)) { + int fd; + + fd = open(name.c_str(), O_RDONLY); + if (fd < 0) { + ALOGE("Cannot open %s", name.c_str()); + return -1; + } + + return registerEpollEntry(usb, name, fd, flags, func); +} + +static void clearUsbDeviceState(struct Usb::usbDeviceState *device) { + device->states.clear(); + device->timestamps.clear(); + device->portResetCount = 0; +} + +static void updateUsbDeviceState(struct Usb::usbDeviceState *device, char *state) { + ALOGI("Update USB device state: %s", state); + + device->states.push_back(state); + device->timestamps.push_back(std::chrono::steady_clock::now()); + + if (!std::strcmp(state, "configured\n")) { + device->portResetCount = 0; + } else if (!std::strcmp(state, "default\n")) { + device->portResetCount++; + } +} + +static void host_event(uint32_t /*epevents*/, struct Usb::payload *payload) { + int n; + char state[USB_STATE_MAX_LEN] = {0}; + struct Usb::usbDeviceState *device; + + lseek(payload->fd, 0, SEEK_SET); + n = read(payload->fd, &state, USB_STATE_MAX_LEN); + + updateUsbDeviceState(&payload->usb->mHostStateMap[payload->name], state); +} + +void queryUsbDataSession(android::hardware::usb::Usb *usb, + std::vector<PortStatus> *currentPortStatus) { + PortDataRole newDataRole = (*currentPortStatus)[0].currentDataRole; + PowerBrickStatus newPowerBrickStatus = (*currentPortStatus)[0].powerBrickStatus; + + if (newDataRole != usb->mDataRole) { + // Upload metrics for the last non-powerbrick data session that has ended + if (usb->mDataRole != PortDataRole::NONE && !usb->mIsPowerBrickConnected) { + report_usb_data_session_event(usb); + } + + // Set up for the new data session + usb->mDataRole = newDataRole; + usb->mDataSessionStart = std::chrono::steady_clock::now(); + usb->mIsPowerBrickConnected = (newPowerBrickStatus == PowerBrickStatus::CONNECTED); + if (newDataRole == PortDataRole::DEVICE) { + clearUsbDeviceState(&usb->mDeviceState); + } else if (newDataRole == PortDataRole::HOST) { + for (auto &entry : usb->mHostStateMap) { + clearUsbDeviceState(&entry.second); + } + } + } + + // PowerBrickStatus could flip from DISCONNECTED to CONNECTED during the same data + // session when BC1.2 SDP times out and falls back to DCP + if (newPowerBrickStatus == PowerBrickStatus::CONNECTED) { + usb->mIsPowerBrickConnected = true; + } +} + +static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) { char msg[UEVENT_MSG_LEN + 2]; char *cp; int n; enum UeventType uevent_type = UeventType::UNKNOWN; + std::cmatch match; - n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN); + n = uevent_kernel_multicast_recv(payload->fd, msg, UEVENT_MSG_LEN); if (n <= 0) return; if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ @@ -1269,6 +1431,28 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) { pthread_mutex_unlock(&payload->usb->mDisplayPortLock); } break; + } else if (std::regex_match(cp, match, std::regex(kHostUeventRegex))) { + /* + * Matched strings: + * 1st: entire string + * 2nd: uevent action, either "bind" or "unbind" + * 3rd: xhci device path, e.g. devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.4.auto + * 4th: usb device number, e.g. 1 for usb1 + * + * The strings are used to composed usb device state path, e.g. + * /sys/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.4.auto/usb2/2-0:1.0/usb2-port1/state + */ + if (match.size() == 4) { + std::string action = match[1].str(); + std::string id = match[3].str(); + std::string path = "/sys" + match[2].str() + "usb" + id + "/" + + id + "-0:1.0/usb" + id + "-port1/state"; + if (action == "bind") { + registerEpollEntryByFile(payload->usb, path, EPOLLPRI, host_event); + } else if (action == "unbind") { + unregisterEpollEntry(payload->usb, path); + } + } } /* advance to after the next \0 */ while (*cp++) { @@ -1276,37 +1460,46 @@ static void uevent_event(uint32_t /*epevents*/, struct data *payload) { } } +static void udc_event(uint32_t /*epevents*/, struct Usb::payload *payload) { + int n; + char state[USB_STATE_MAX_LEN] = {0}; + + lseek(payload->fd, 0, SEEK_SET); + n = read(payload->fd, &state, USB_STATE_MAX_LEN); + + updateUsbDeviceState(&payload->usb->mDeviceState, state); +} + void *work(void *param) { int epoll_fd, uevent_fd; - struct epoll_event ev; int nevents = 0; - struct data payload; + Usb *usb = (Usb *)param; ALOGE("creating thread"); - uevent_fd = uevent_open_socket(64 * 1024, true); - - if (uevent_fd < 0) { - ALOGE("uevent_init: uevent_open_socket failed\n"); + epoll_fd = epoll_create(64); + if (epoll_fd == -1) { + ALOGE("epoll_create failed; errno=%d", errno); return NULL; } + usb->mEpollFd = epoll_fd; - payload.uevent_fd = uevent_fd; - payload.usb = (::aidl::android::hardware::usb::Usb *)param; - + // Monitor uevent + uevent_fd = uevent_open_socket(64 * 1024, true); + if (uevent_fd < 0) { + ALOGE("uevent_init: uevent_open_socket failed"); + goto error; + } fcntl(uevent_fd, F_SETFL, O_NONBLOCK); - ev.events = EPOLLIN; - ev.data.ptr = (void *)uevent_event; - - epoll_fd = epoll_create(64); - if (epoll_fd == -1) { - ALOGE("epoll_create failed; errno=%d", errno); + if (registerEpollEntry(usb, "uevent", uevent_fd, EPOLLIN, uevent_event)) { + ALOGE("failed to monitor uevent"); goto error; } - if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) { - ALOGE("epoll_ctl failed; errno=%d", errno); + // Monitor udc state + if (registerEpollEntryByFile(usb, kUdcState, EPOLLPRI, udc_event)) { + ALOGE("failed to monitor udc state"); goto error; } @@ -1323,14 +1516,15 @@ void *work(void *param) { for (int n = 0; n < nevents; ++n) { if (events[n].data.ptr) - (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events, - &payload); + (*(std::function<void(uint32_t)>*)events[n].data.ptr)(events[n].events); } } ALOGI("exiting worker thread"); error: - close(uevent_fd); + unregisterEpollEntries(usb); + + usb->mEpollFd = -1; if (epoll_fd >= 0) close(epoll_fd); diff --git a/usb/usb/Usb.h b/usb/usb/Usb.h index 4d9ab53..c1e5354 100644 --- a/usb/usb/Usb.h +++ b/usb/usb/Usb.h @@ -19,10 +19,10 @@ #include <android-base/file.h> #include <aidl/android/hardware/usb/BnUsb.h> #include <aidl/android/hardware/usb/BnUsbCallback.h> +#include <chrono> #include <pixelusb/UsbOverheatEvent.h> #include <sys/eventfd.h> #include <utils/Log.h> -#include <UsbDataSessionMonitor.h> #define UEVENT_MSG_LEN 2048 // The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd. @@ -121,8 +121,6 @@ struct Usb : public BnUsb { // Variable to signal partner coming back online after type switch bool mPartnerUp; - // Report usb data session event and data incompliance warnings - UsbDataSessionMonitor mUsbDataSessionMonitor; // Usb Overheat object for push suez event UsbOverheatEvent mOverheat; // Temperature when connected @@ -145,6 +143,36 @@ struct Usb : public BnUsb { // eventfd to signal DisplayPort thread int mDisplayPortEventPipe; + // USB device state monitoring + struct usbDeviceState { + // Usb device state raw strings read from sysfs + std::vector<std::string> states; + // Timestamps of when the usb device states were captured + std::vector<std::chrono::steady_clock::time_point> timestamps; + int portResetCount; + }; + struct usbDeviceState mDeviceState; + // Map host device path name to usbDeviceState + std::map<std::string, struct usbDeviceState> mHostStateMap; + // Cache relevant info for USB data session metrics collection when a session starts, including + // the data role, power brick status and the time when the session starts. + PortDataRole mDataRole; + bool mIsPowerBrickConnected; + std::chrono::steady_clock::time_point mDataSessionStart; + + // File monitoring through epoll + int mEpollFd; + struct payload { + int fd; + std::string name; + Usb *usb; + }; + struct epollEntry { + struct payload payload; + std::function<void(uint32_t)> cb; + }; + std::map<std::string, struct epollEntry> mEpollEntries; + /* * eventfd to set DisplayPort framework update debounce timer. Debounce timer is necessary for * 1) allowing enough time for each sysfs node needed to set HPD high in the drm to populate diff --git a/usb/usb/UsbDataSessionMonitor.cpp b/usb/usb/UsbDataSessionMonitor.cpp deleted file mode 100644 index 77defb3..0000000 --- a/usb/usb/UsbDataSessionMonitor.cpp +++ /dev/null @@ -1,420 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "android.hardware.usb.aidl-service.UsbDataSessionMonitor" - -#include "UsbDataSessionMonitor.h" - -#include <aidl/android/frameworks/stats/IStats.h> -#include <android-base/file.h> -#include <android-base/logging.h> -#include <android_hardware_usb_flags.h> -#include <cutils/uevent.h> -#include <pixelstats/StatsHelper.h> -#include <pixelusb/CommonUtils.h> -#include <sys/epoll.h> -#include <utils/Log.h> - -#include <regex> - -namespace usb_flags = android::hardware::usb::flags; - -using aidl::android::frameworks::stats::IStats; -using android::base::ReadFileToString; -using android::hardware::google::pixel::getStatsService; -using android::hardware::google::pixel::reportUsbDataSessionEvent; -using android::hardware::google::pixel::PixelAtoms::VendorUsbDataSessionEvent; -using android::hardware::google::pixel::usb::addEpollFd; -using android::hardware::google::pixel::usb::BuildVendorUsbDataSessionEvent; - -namespace aidl { -namespace android { -namespace hardware { -namespace usb { - -#define UEVENT_MSG_LEN 2048 -#define USB_STATE_MAX_LEN 20 -#define DATA_ROLE_MAX_LEN 10 - -constexpr char kUdcConfigfsPath[] = "/config/usb_gadget/g1/UDC"; -constexpr char kNotAttachedState[] = "not attached\n"; -constexpr char kAttachedState[] = "attached\n"; -constexpr char kPoweredState[] = "powered\n"; -constexpr char kDefaultState[] = "default\n"; -constexpr char kAddressedState[] = "addressed\n"; -constexpr char kConfiguredState[] = "configured\n"; -constexpr char kSuspendedState[] = "suspended\n"; -const std::set<std::string> kValidStates = {kNotAttachedState, kAttachedState, kPoweredState, - kDefaultState, kAddressedState, kConfiguredState, - kSuspendedState}; - -static int addEpollFile(const int &epollFd, const std::string &filePath, unique_fd &fileFd) { - struct epoll_event ev; - - unique_fd fd(open(filePath.c_str(), O_RDONLY)); - - if (fd.get() == -1) { - ALOGI("Cannot open %s", filePath.c_str()); - return -1; - } - - ev.data.fd = fd.get(); - ev.events = EPOLLPRI; - - if (epoll_ctl(epollFd, EPOLL_CTL_ADD, fd.get(), &ev) != 0) { - ALOGE("epoll_ctl failed; errno=%d", errno); - return -1; - } - - fileFd = std::move(fd); - ALOGI("epoll registered %s", filePath.c_str()); - return 0; -} - -static void removeEpollFile(const int &epollFd, const std::string &filePath, unique_fd &fileFd) { - epoll_ctl(epollFd, EPOLL_CTL_DEL, fileFd.get(), NULL); - fileFd.release(); - - ALOGI("epoll unregistered %s", filePath.c_str()); -} - -UsbDataSessionMonitor::UsbDataSessionMonitor( - const std::string &deviceUeventRegex, const std::string &deviceStatePath, - const std::string &host1UeventRegex, const std::string &host1StatePath, - const std::string &host2UeventRegex, const std::string &host2StatePath, - const std::string &dataRolePath, std::function<void()> updatePortStatusCb) { - struct epoll_event ev; - std::string udc; - - unique_fd epollFd(epoll_create(8)); - if (epollFd.get() == -1) { - ALOGE("epoll_create failed; errno=%d", errno); - abort(); - } - - unique_fd ueventFd(uevent_open_socket(64 * 1024, true)); - if (ueventFd.get() == -1) { - ALOGE("uevent_open_socket failed"); - abort(); - } - fcntl(ueventFd, F_SETFL, O_NONBLOCK); - - if (addEpollFd(epollFd, ueventFd)) - abort(); - - if (addEpollFile(epollFd.get(), dataRolePath, mDataRoleFd) != 0) { - ALOGE("monitor data role failed"); - abort(); - } - - /* - * The device state file could be absent depending on the current data role - * and driver architecture. It's ok for addEpollFile to fail here, the file - * will be monitored later when its presence is detected by uevent. - */ - mDeviceState.filePath = deviceStatePath; - mDeviceState.ueventRegex = deviceUeventRegex; - addEpollFile(epollFd.get(), mDeviceState.filePath, mDeviceState.fd); - - mHost1State.filePath = host1StatePath; - mHost1State.ueventRegex = host1UeventRegex; - addEpollFile(epollFd.get(), mHost1State.filePath, mHost1State.fd); - - mHost2State.filePath = host2StatePath; - mHost2State.ueventRegex = host2UeventRegex; - addEpollFile(epollFd.get(), mHost2State.filePath, mHost2State.fd); - - mEpollFd = std::move(epollFd); - mUeventFd = std::move(ueventFd); - mUpdatePortStatusCb = updatePortStatusCb; - - if (ReadFileToString(kUdcConfigfsPath, &udc) && !udc.empty()) - mUdcBind = true; - else - mUdcBind = false; - - if (pthread_create(&mMonitor, NULL, this->monitorThread, this)) { - ALOGE("pthread creation failed %d", errno); - abort(); - } -} - -UsbDataSessionMonitor::~UsbDataSessionMonitor() {} - -void UsbDataSessionMonitor::reportUsbDataSessionMetrics() { - std::vector<VendorUsbDataSessionEvent> events; - - if (mDataRole == PortDataRole::DEVICE) { - VendorUsbDataSessionEvent event; - BuildVendorUsbDataSessionEvent(false /* is_host */, boot_clock::now(), mDataSessionStart, - &mDeviceState.states, &mDeviceState.timestamps, &event); - events.push_back(event); - } else if (mDataRole == PortDataRole::HOST) { - bool empty = true; - for (auto e : {&mHost1State, &mHost2State}) { - /* - * Host port will at least get an not_attached event after enablement, - * skip upload if no additional state is added. - */ - if (e->states.size() > 1) { - VendorUsbDataSessionEvent event; - BuildVendorUsbDataSessionEvent(true /* is_host */, boot_clock::now(), - mDataSessionStart, &e->states, &e->timestamps, - &event); - events.push_back(event); - empty = false; - } - } - // All host ports have no state update, upload an event to reflect it - if (empty) { - VendorUsbDataSessionEvent event; - BuildVendorUsbDataSessionEvent(true /* is_host */, boot_clock::now(), mDataSessionStart, - &mHost1State.states, &mHost1State.timestamps, &event); - events.push_back(event); - } - } else { - return; - } - - const std::shared_ptr<IStats> stats_client = getStatsService(); - if (!stats_client) { - ALOGE("Unable to get AIDL Stats service"); - return; - } - - for (auto &event : events) { - reportUsbDataSessionEvent(stats_client, event); - } -} - -void UsbDataSessionMonitor::getComplianceWarnings(const PortDataRole &role, - std::vector<ComplianceWarning> *warnings) { - if (!usb_flags::enable_report_usb_data_compliance_warning()) - return; - - if (role != mDataRole || role == PortDataRole::NONE) - return; - - for (auto w : mWarningSet) { - warnings->push_back(w); - } -} - -void UsbDataSessionMonitor::notifyComplianceWarning() { - if (!usb_flags::enable_report_usb_data_compliance_warning()) - return; - - if (mUpdatePortStatusCb) - mUpdatePortStatusCb(); -} - -void UsbDataSessionMonitor::evaluateComplianceWarning() { - std::set<ComplianceWarning> newWarningSet; - - // TODO: add heuristics and update newWarningSet - if (mDataRole == PortDataRole::DEVICE && mUdcBind) { - } else if (mDataRole == PortDataRole::HOST) { - } - - if (newWarningSet != mWarningSet) { - mWarningSet = newWarningSet; - notifyComplianceWarning(); - } -} - -void UsbDataSessionMonitor::clearDeviceStateEvents(struct usbDeviceState *deviceState) { - deviceState->states.clear(); - deviceState->timestamps.clear(); -} - -void UsbDataSessionMonitor::handleDeviceStateEvent(struct usbDeviceState *deviceState) { - int n; - char state[USB_STATE_MAX_LEN] = {0}; - - lseek(deviceState->fd.get(), 0, SEEK_SET); - n = read(deviceState->fd.get(), &state, USB_STATE_MAX_LEN); - - if (kValidStates.find(state) == kValidStates.end()) { - ALOGE("Invalid state %s", state); - return; - } - - ALOGI("Update USB device state: %s", state); - - deviceState->states.push_back(state); - deviceState->timestamps.push_back(boot_clock::now()); - evaluateComplianceWarning(); -} - -void UsbDataSessionMonitor::handleDataRoleEvent() { - int n; - PortDataRole newDataRole; - char role[DATA_ROLE_MAX_LEN] = {0}; - - lseek(mDataRoleFd.get(), 0, SEEK_SET); - n = read(mDataRoleFd.get(), &role, DATA_ROLE_MAX_LEN); - - ALOGI("Update USB data role %s", role); - - if (!std::strcmp(role, "host")) { - newDataRole = PortDataRole::HOST; - } else if (!std::strcmp(role, "device")) { - newDataRole = PortDataRole::DEVICE; - } else { - newDataRole = PortDataRole::NONE; - } - - if (newDataRole != mDataRole) { - // Upload metrics for the last data session that has ended - if (mDataRole == PortDataRole::HOST || (mDataRole == PortDataRole::DEVICE && mUdcBind)) { - reportUsbDataSessionMetrics(); - } - - // Set up for the new data session - mWarningSet.clear(); - mDataRole = newDataRole; - mDataSessionStart = boot_clock::now(); - - if (newDataRole == PortDataRole::DEVICE) { - clearDeviceStateEvents(&mDeviceState); - } else if (newDataRole == PortDataRole::HOST) { - clearDeviceStateEvents(&mHost1State); - clearDeviceStateEvents(&mHost2State); - } - } -} - -void UsbDataSessionMonitor::updateUdcBindStatus(const std::string &devname) { - std::string function; - bool newUdcBind; - - /* - * /sys/class/udc/<udc>/function prints out name of currently running USB gadget driver - * Ref: https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-class-udc - * Empty name string means the udc device is not bound and gadget is pulldown. - */ - if (!ReadFileToString("/sys" + devname + "/function", &function)) - return; - - if (function == "") - newUdcBind = false; - else - newUdcBind = true; - - if (newUdcBind == mUdcBind) - return; - - if (mDataRole == PortDataRole::DEVICE) { - if (mUdcBind && !newUdcBind) { - /* - * Gadget soft pulldown: report metrics as the end of a data session and - * re-evaluate compliance warnings to clear existing warnings if any. - */ - reportUsbDataSessionMetrics(); - evaluateComplianceWarning(); - - } else if (!mUdcBind && newUdcBind) { - // Gadget soft pullup: reset and start accounting for a new data session. - clearDeviceStateEvents(&mDeviceState); - mDataSessionStart = boot_clock::now(); - } - } - - ALOGI("Udc bind status changes from %b to %b", mUdcBind, newUdcBind); - mUdcBind = newUdcBind; -} - -void UsbDataSessionMonitor::handleUevent() { - char msg[UEVENT_MSG_LEN + 2]; - char *cp; - int n; - - n = uevent_kernel_multicast_recv(mUeventFd.get(), msg, UEVENT_MSG_LEN); - if (n <= 0) - return; - if (n >= UEVENT_MSG_LEN) - return; - - msg[n] = '\0'; - msg[n + 1] = '\0'; - cp = msg; - - while (*cp) { - for (auto e : {&mHost1State, &mHost2State}) { - if (std::regex_search(cp, std::regex(e->ueventRegex))) { - if (!strncmp(cp, "bind@", strlen("bind@"))) { - addEpollFile(mEpollFd.get(), e->filePath, e->fd); - } else if (!strncmp(cp, "unbind@", strlen("unbind@"))) { - removeEpollFile(mEpollFd.get(), e->filePath, e->fd); - } - } - } - - // TODO: support bind@ unbind@ to detect dynamically allocated udc device - if (std::regex_search(cp, std::regex(mDeviceState.ueventRegex))) { - if (!strncmp(cp, "change@", strlen("change@"))) { - char *devname = cp + strlen("change@"); - /* - * Udc device emits a KOBJ_CHANGE event on configfs driver bind and unbind. - * TODO: upstream udc driver emits KOBJ_CHANGE event BEFORE unbind is actually - * executed. Add a short delay to get the correct state while working on a fix - * upstream. - */ - usleep(50000); - updateUdcBindStatus(devname); - } - } - /* advance to after the next \0 */ - while (*cp++) { - } - } -} - -void *UsbDataSessionMonitor::monitorThread(void *param) { - UsbDataSessionMonitor *monitor = (UsbDataSessionMonitor *)param; - struct epoll_event events[64]; - int nevents = 0; - - while (true) { - nevents = epoll_wait(monitor->mEpollFd.get(), events, 64, -1); - if (nevents == -1) { - if (errno == EINTR) - continue; - ALOGE("usb epoll_wait failed; errno=%d", errno); - break; - } - - for (int n = 0; n < nevents; ++n) { - if (events[n].data.fd == monitor->mUeventFd.get()) { - monitor->handleUevent(); - } else if (events[n].data.fd == monitor->mDataRoleFd.get()) { - monitor->handleDataRoleEvent(); - } else if (events[n].data.fd == monitor->mDeviceState.fd.get()) { - monitor->handleDeviceStateEvent(&monitor->mDeviceState); - } else if (events[n].data.fd == monitor->mHost1State.fd.get()) { - monitor->handleDeviceStateEvent(&monitor->mHost1State); - } else if (events[n].data.fd == monitor->mHost2State.fd.get()) { - monitor->handleDeviceStateEvent(&monitor->mHost2State); - } - } - } - return NULL; -} - -} // namespace usb -} // namespace hardware -} // namespace android -} // namespace aidl diff --git a/usb/usb/UsbDataSessionMonitor.h b/usb/usb/UsbDataSessionMonitor.h deleted file mode 100644 index 596f378..0000000 --- a/usb/usb/UsbDataSessionMonitor.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright (C) 2023 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include <aidl/android/hardware/usb/ComplianceWarning.h> -#include <aidl/android/hardware/usb/PortDataRole.h> -#include <android-base/chrono_utils.h> -#include <android-base/unique_fd.h> - -#include <set> -#include <string> -#include <vector> - -namespace aidl { -namespace android { -namespace hardware { -namespace usb { - -using ::aidl::android::hardware::usb::ComplianceWarning; -using ::aidl::android::hardware::usb::PortDataRole; -using ::android::base::boot_clock; -using ::android::base::unique_fd; - -/* - * UsbDataSessionMonitor monitors the usb device state sysfs of 3 different usb devices - * including device mode (udc), host mode high-speed port and host mode super-speed port. It - * reports Suez metrics for each data session and also provides API to query the compliance - * warnings detected in the current usb data session. - */ -class UsbDataSessionMonitor { - public: - /* - * The host mode high-speed port and super-speed port can be assigned to either host1 or - * host2 without affecting functionality. - * - * UeventRegex: name regex of the device that's being monitored. The regex is matched against - * uevent to detect dynamic creation/deletion/change of the device. - * StatePath: usb device state sysfs path of the device, monitored by epoll. - * dataRolePath: path to the usb data role sysfs, monitored by epoll. - * updatePortStatusCb: the callback is invoked when the compliance warings changes. - */ - UsbDataSessionMonitor(const std::string &deviceUeventRegex, const std::string &deviceStatePath, - const std::string &host1UeventRegex, const std::string &host1StatePath, - const std::string &host2UeventRegex, const std::string &host2StatePath, - const std::string &dataRolePath, - std::function<void()> updatePortStatusCb); - ~UsbDataSessionMonitor(); - // Returns the compliance warnings detected in the current data session. - void getComplianceWarnings(const PortDataRole &role, std::vector<ComplianceWarning> *warnings); - - private: - struct usbDeviceState { - unique_fd fd; - std::string filePath; - std::string ueventRegex; - // Usb device states reported by state sysfs - std::vector<std::string> states; - // Timestamps of when the usb device states were captured - std::vector<boot_clock::time_point> timestamps; - }; - - static void *monitorThread(void *param); - void handleUevent(); - void handleDataRoleEvent(); - void handleDeviceStateEvent(struct usbDeviceState *deviceState); - void clearDeviceStateEvents(struct usbDeviceState *deviceState); - void reportUsbDataSessionMetrics(); - void evaluateComplianceWarning(); - void notifyComplianceWarning(); - void updateUdcBindStatus(const std::string &devname); - - pthread_t mMonitor; - unique_fd mEpollFd; - unique_fd mUeventFd; - unique_fd mDataRoleFd; - struct usbDeviceState mDeviceState; - struct usbDeviceState mHost1State; - struct usbDeviceState mHost2State; - std::set<ComplianceWarning> mWarningSet; - // Callback function to notify the caller when there's a change in compliance warnings. - std::function<void()> mUpdatePortStatusCb; - /* - * Cache relevant info for a USB data session when one starts, including - * the data role and the time when the session starts. - */ - PortDataRole mDataRole; - boot_clock::time_point mDataSessionStart; - /* - * In gadget mode: this indicates whether the udc device is bound to the configfs driver, which - * is done by userspace writing the udc device name to /config/usb_gadget/g1/UDC. When unbound, - * the gadget is in soft pulldown state and is expected not to enumerate. During gadget - * function switch, the udc device usually go through unbind and bind. - */ - bool mUdcBind; -}; - -} // namespace usb -} // namespace hardware -} // namespace android -} // namespace aidl |