diff --git a/conf/init.gs201.rc b/conf/init.gs201.rc index ae03ce9a..4c6da6df 100644 --- a/conf/init.gs201.rc +++ b/conf/init.gs201.rc @@ -934,13 +934,13 @@ on post-fs-data on property:vendor.brownout.mitigation.ready=1 # BCL - write /sys/devices/virtual/pmic/mitigation/clock_ratio/tpu_light_clk_ratio 0xfff041c1 #DFS - write /sys/devices/virtual/pmic/mitigation/clock_ratio/cpu1_heavy_clk_ratio 0xfff041c1 #DFS - write /sys/devices/virtual/pmic/mitigation/clock_ratio/cpu2_heavy_clk_ratio 0xfff041c1 #DFS - write /sys/devices/virtual/pmic/mitigation/clock_ratio/gpu_light_clk_ratio 0xfff041c1 #DFS + write /sys/devices/virtual/pmic/mitigation/clock_ratio/tpu_light_clk_ratio 0x80041c3 #DFS + write /sys/devices/virtual/pmic/mitigation/clock_ratio/cpu1_heavy_clk_ratio 0xfff041c0 #DFS + write /sys/devices/virtual/pmic/mitigation/clock_ratio/cpu2_heavy_clk_ratio 0xfff041c0 #DFS + write /sys/devices/virtual/pmic/mitigation/clock_ratio/gpu_light_clk_ratio 0x80041c3 #DFS write /sys/devices/virtual/pmic/mitigation/clock_ratio/cpu2_light_clk_ratio 0xfff041c3 #OCP - write /sys/devices/virtual/pmic/mitigation/clock_ratio/gpu_heavy_clk_ratio 0xfff04385 #OCP - write /sys/devices/virtual/pmic/mitigation/clock_ratio/tpu_heavy_clk_ratio 0xfff041c3 #OCP + write /sys/devices/virtual/pmic/mitigation/clock_ratio/gpu_heavy_clk_ratio 0xfff04381 #OCP + write /sys/devices/virtual/pmic/mitigation/clock_ratio/tpu_heavy_clk_ratio 0xfff041c1 #OCP write /sys/devices/virtual/pmic/mitigation/triggered_lvl/uvlo1_lvl 3200 write /sys/devices/virtual/pmic/mitigation/triggered_lvl/smpl_lvl 3100 write /sys/devices/virtual/pmic/mitigation/triggered_lvl/uvlo2_lvl 3000 diff --git a/conf/init.gs201.usb.rc b/conf/init.gs201.usb.rc index 6a52fb07..9ba9eb8a 100644 --- a/conf/init.gs201.usb.rc +++ b/conf/init.gs201.usb.rc @@ -371,6 +371,8 @@ on boot write sys/module/usbcore/parameters/initial_descriptor_timeout 500 # Use USB Gadget HAL setprop sys.usb.configfs 2 + # Enable in-kernel media-presence polling for SD cards + write /sys/module/block/parameters/events_dfl_poll_msecs 2000 on property:sys.usb.ffs.ready=1 && property:sys.usb.config=adb && property:sys.usb.configfs=1 write /config/usb_gadget/g1/idProduct 0x4EE7 diff --git a/device.mk b/device.mk index 4342a53a..d15c21d4 100644 --- a/device.mk +++ b/device.mk @@ -36,6 +36,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 TARGET_BOARD_PLATFORM := gs201 @@ -191,7 +192,7 @@ PRODUCT_PRODUCT_PROPERTIES += \ # Carrier configuration default location PRODUCT_PROPERTY_OVERRIDES += \ - persist.vendor.radio.config.carrier_config_dir=/mnt/vendor/modem_img/images/default/confpack + persist.vendor.radio.config.carrier_config_dir=/vendor/firmware/carrierconfig PRODUCT_PROPERTY_OVERRIDES += \ telephony.active_modems.max_count=2 @@ -922,11 +923,6 @@ PRODUCT_PACKAGES_DEBUG += \ PRODUCT_PACKAGES += ShannonRcs endif -# Boot Control HAL -PRODUCT_PACKAGES += \ - android.hardware.boot@1.2-impl-gs201 \ - android.hardware.boot@1.2-service-gs201 - # 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 a5937e78..00000000 --- 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/gs201:device_google_gs201_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: [ - "//device/google/gs201:device_google_gs201_license", - ], -} - -cc_binary { - name: "android.hardware.boot@1.0-service-gs201", - defaults: ["hidl_defaults"], - relative_install_path: "hw", - vendor: true, - init_rc: ["android.hardware.boot@1.0-service-gs201.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-gs201", - 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 1f155c9d..00000000 --- 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 -#include -#include - -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 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 BootControl::getCurrentSlot() { - char suffix[PROPERTY_VALUE_MAX]; - property_get("ro.boot.slot_suffix", suffix, "_a"); - return std::string(suffix) == "_b" ? 1 : 0; -} - -Return 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 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 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 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 eb81cb07..00000000 --- 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 -#include -#include - -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 getNumberSlots() override; - Return getCurrentSlot() override; - Return markBootSuccessful(markBootSuccessful_cb _hidl_cb) override; - Return setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) override; - Return 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 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 f8936175..00000000 --- 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 -#include -#include -#include -#include - -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 - 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(&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(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(&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(&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 d969d9d8..00000000 --- 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 -#include -#include - -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 entry_array; - std::mapentries; -}; - -} // namespace implementation -} // namespace V1_0 -} // namespace boot -} // namespace hardware -} // namespace android diff --git a/interfaces/boot/1.0/android.hardware.boot@1.0-service-gs201.rc b/interfaces/boot/1.0/android.hardware.boot@1.0-service-gs201.rc deleted file mode 100644 index 7a7849fd..00000000 --- a/interfaces/boot/1.0/android.hardware.boot@1.0-service-gs201.rc +++ /dev/null @@ -1,4 +0,0 @@ -service vendor.boot-hal-1-0 /vendor/bin/hw/android.hardware.boot@1.0-service-gs201 - 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 9dcd78cc..00000000 --- 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 -#include -#include -#include -#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 a9fb7f49..00000000 --- a/interfaces/boot/1.2/Android.bp +++ /dev/null @@ -1,81 +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/gs201:device_google_gs201_license" - // to get the below license kinds: - // SPDX-license-identifier-Apache-2.0 - default_applicable_licenses: [ - "//device/google/gs201:device_google_gs201_license", - ], -} - -cc_binary { - name: "android.hardware.boot@1.2-service-gs201", - defaults: ["hidl_defaults"], - relative_install_path: "hw", - vendor: true, - init_rc: ["android.hardware.boot@1.2-service-gs201.rc"], - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - "service.cpp" - ], - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libutils", - "libcutils", - "libz", - "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-gs201", - stem: "android.hardware.boot@1.0-impl-1.2-impl-gs201", - recovery: true, - srcs: [ - "BootControl.cpp", - "GptUtils.cpp", - ], - relative_install_path: "hw", - shared_libs: [ - "libbase", - "liblog", - "libhidlbase", - "libutils", - "libcutils", - "libz", - "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 a28be05a..00000000 --- a/interfaces/boot/1.2/BootControl.cpp +++ /dev/null @@ -1,420 +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 -#include -#include -#include -#include -#include - -#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 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; -} - -} // namespace - -// Methods from ::android::hardware::boot::V1_0::IBootControl follow. -Return 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 BootControl::getCurrentSlot() { - char suffix[PROPERTY_VALUE_MAX]; - property_get("ro.boot.slot_suffix", suffix, "_a"); - return std::string(suffix) == "_b" ? 1 : 0; -} - -Return 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); - } - - !ret ? _hidl_cb({false, "Failed to set successful flag"}) : _hidl_cb({true, ""}); - return Void(); -} - -Return 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 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 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 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 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 17b5f0fb..00000000 --- a/interfaces/boot/1.2/BootControl.h +++ /dev/null @@ -1,69 +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 -#include -#include - -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 getNumberSlots() override; - Return getCurrentSlot() override; - Return markBootSuccessful(markBootSuccessful_cb _hidl_cb) override; - Return setActiveBootSlot(uint32_t slot, setActiveBootSlot_cb _hidl_cb) override; - Return 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 getSuffix(uint32_t slot, getSuffix_cb _hidl_cb) override; - - // Methods from ::android::hardware::boot::V1_1::IBootControl follow. - Return 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 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); - -} // 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 a09a83a2..00000000 --- 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 25088e79..00000000 --- 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 -#include -#include -#include -#include - -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 - 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(&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(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(&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(&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 a2bed334..00000000 --- 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 -#include -#include - -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 entry_array; - std::map 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-gs201.rc b/interfaces/boot/1.2/android.hardware.boot@1.2-service-gs201.rc deleted file mode 100644 index 3457b5f0..00000000 --- a/interfaces/boot/1.2/android.hardware.boot@1.2-service-gs201.rc +++ /dev/null @@ -1,7 +0,0 @@ -service vendor.boot-hal-1-2 /vendor/bin/hw/android.hardware.boot@1.2-service-gs201 - 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 diff --git a/interfaces/boot/1.2/service.cpp b/interfaces/boot/1.2/service.cpp deleted file mode 100644 index f07682e9..00000000 --- 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 -#include -#include -#include - -#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/manifest-gralloc3.xml b/manifest-gralloc3.xml index 82ff14ab..cd405200 100644 --- a/manifest-gralloc3.xml +++ b/manifest-gralloc3.xml @@ -68,10 +68,9 @@ default - + android.hardware.boot - hwbinder - @1.2::IBootControl/default + IBootControl/default android.hardware.sensors diff --git a/manifest.xml b/manifest.xml index 031b46f3..a5cf98dc 100644 --- a/manifest.xml +++ b/manifest.xml @@ -8,10 +8,9 @@ default - + android.hardware.boot - hwbinder - @1.2::IBootControl/default + IBootControl/default com.google.input diff --git a/overlay/frameworks/base/core/res/res/values/config.xml b/overlay/frameworks/base/core/res/res/values/config.xml index f2ed7789..e9e4f01b 100644 --- a/overlay/frameworks/base/core/res/res/values/config.xml +++ b/overlay/frameworks/base/core/res/res/values/config.xml @@ -215,7 +215,7 @@ - 3339 + 4000 true @@ -252,6 +252,9 @@ true + + 20971520 + diff --git a/pixelstats/service.cpp b/pixelstats/service.cpp index 5d739b18..ab6f85f2 100644 --- a/pixelstats/service.cpp +++ b/pixelstats/service.cpp @@ -71,7 +71,7 @@ const struct SysfsCollector::SysfsPaths sysfs_paths = { "/sys/devices/platform/100b0000.TPU/trip_counter", "/sys/devices/platform/100b0000.AUR/trip_counter", }, - .CCARatePath = "/sys/devices/platform/audiometrics/cca_rate_read_once", + .CCARatePath = "/sys/devices/platform/audiometrics/cca_count_read_once", .TempResidencyAndResetPaths = { { "/sys/kernel/metrics/thermal/tr_by_group/tmu/stats", @@ -88,7 +88,8 @@ const struct SysfsCollector::SysfsPaths sysfs_paths = { .IRQStatsResetPath = "/sys/kernel/metrics/irq/stats_reset", .ModemPcieLinkStatsPath = "/sys/devices/platform/11920000.pcie/link_stats", .WifiPcieLinkStatsPath = "/sys/devices/platform/14520000.pcie/link_stats", - .GMSRPath = "/sys/class/power_supply/maxfg/gmsr" + .GMSRPath = "/sys/class/power_supply/maxfg/gmsr", + .TotalCallCountPath = "/sys/devices/platform/audiometrics/call_count" }; const struct UeventListener::UeventPaths ueventPaths = { diff --git a/usb/usb/Android.bp b/usb/usb/Android.bp index 8fd373b2..609af179 100644 --- a/usb/usb/Android.bp +++ b/usb/usb/Android.bp @@ -34,6 +34,7 @@ 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 224951a1..555e6576 100644 --- a/usb/usb/Usb.cpp +++ b/usb/usb/Usb.cpp @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -44,7 +43,6 @@ #include #include -#include #include #include @@ -57,9 +55,6 @@ 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; using android::String8; using android::Vector; @@ -95,17 +90,22 @@ constexpr char kThermalZoneForTempReadSecondary2[] = "qi_therm"; constexpr char kPogoUsbActive[] = "/sys/devices/platform/google,pogo/pogo_usb_active"; constexpr char KPogoMoveDataToUsb[] = "/sys/devices/platform/google,pogo/move_data_to_usb"; constexpr char kPowerSupplyUsbType[] = "/sys/class/power_supply/usb/usb_type"; -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 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/usb2/2-0:1.0"; +constexpr char kHost1StatePath[] = "/sys/bus/usb/devices/usb2/2-0:1.0/usb2-port1/state"; +constexpr char kHost2UeventRegex[] = + "/devices/platform/11210000.usb/11210000.dwc3/xhci-hcd-exynos.[0-9].auto/usb3/3-0:1.0"; +constexpr char kHost2StatePath[] = "/sys/bus/usb/devices/usb3/3-0:1.0/usb3-port1/state"; +constexpr char kDataRolePath[] = "/sys/devices/platform/11210000.usb/new_data_role"; constexpr int kSamplingIntervalSec = 5; void queryVersionHelper(android::hardware::usb::Usb *usb, std::vector *currentPortStatus); -void queryUsbDataSession(android::hardware::usb::Usb *usb, - std::vector *currentPortStatus); -#define USB_STATE_MAX_LEN 20 #define CTRL_TRANSFER_TIMEOUT_MSEC 1000 #define GL852G_VENDOR_ID 0x05e3 #define GL852G_PRODUCT_ID1 0x0608 @@ -538,11 +538,20 @@ void *usbHostWork(void *param) { return NULL; } +void updatePortStatus(android::hardware::usb::Usb *usb) { + std::vector 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, @@ -922,6 +931,18 @@ done: return Status::ERROR; } +void queryUsbDataSession(android::hardware::usb::Usb *usb, + std::vector *currentPortStatus) { + std::vector 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 *currentPortStatus) { Status status; @@ -1017,194 +1038,17 @@ void report_overheat_event(android::hardware::usb::Usb *usb) { } } -void report_usb_data_session_event(android::hardware::usb::Usb *usb) { - std::vector events; +struct data { + int uevent_fd; + ::aidl::android::hardware::usb::Usb *usb; +}; - 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 stats_client = getStatsService(); - if (!stats_client) { - ALOGE("Unable to get AIDL Stats service"); - return; - } - - for (auto &event : events) { - reportUsbDataSessionEvent(stats_client, event); - } -} - -static void unregisterEpollEntry(Usb *usb, std::string name) { - std::map *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 *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 *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 *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) { +static void uevent_event(uint32_t /*epevents*/, struct data *payload) { char msg[UEVENT_MSG_LEN + 2]; char *cp; int n; - std::cmatch match; - n = uevent_kernel_multicast_recv(payload->fd, msg, UEVENT_MSG_LEN); + n = uevent_kernel_multicast_recv(payload->uevent_fd, msg, UEVENT_MSG_LEN); if (n <= 0) return; if (n >= UEVENT_MSG_LEN) /* overflow -- discard */ @@ -1250,28 +1094,6 @@ static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *payload) { } else if (!strncmp(cp, kOverheatStatsDev, strlen(kOverheatStatsDev))) { ALOGV("Overheat Cooling device suez update"); report_overheat_event(payload->usb); - } 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++) { @@ -1279,46 +1101,37 @@ static void uevent_event(uint32_t /*epevents*/, struct Usb::payload *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; - Usb *usb = (Usb *)param; + struct data payload; ALOGE("creating thread"); + uevent_fd = uevent_open_socket(64 * 1024, true); + + if (uevent_fd < 0) { + ALOGE("uevent_init: uevent_open_socket failed\n"); + return NULL; + } + + payload.uevent_fd = uevent_fd; + payload.usb = (::aidl::android::hardware::usb::Usb *)param; + + 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); - return NULL; - } - usb->mEpollFd = epoll_fd; - - // 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); - - if (registerEpollEntry(usb, "uevent", uevent_fd, EPOLLIN, uevent_event)) { - ALOGE("failed to monitor uevent"); goto error; } - // Monitor udc state - if (registerEpollEntryByFile(usb, kUdcState, EPOLLPRI, udc_event)) { - ALOGE("failed to monitor udc state"); + if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, uevent_fd, &ev) == -1) { + ALOGE("epoll_ctl failed; errno=%d", errno); goto error; } @@ -1335,15 +1148,14 @@ void *work(void *param) { for (int n = 0; n < nevents; ++n) { if (events[n].data.ptr) - (*(std::function*)events[n].data.ptr)(events[n].events); + (*(void (*)(int, struct data *payload))events[n].data.ptr)(events[n].events, + &payload); } } ALOGI("exiting worker thread"); error: - unregisterEpollEntries(usb); - - usb->mEpollFd = -1; + close(uevent_fd); if (epoll_fd >= 0) close(epoll_fd); diff --git a/usb/usb/Usb.h b/usb/usb/Usb.h index 83bae889..495a467f 100644 --- a/usb/usb/Usb.h +++ b/usb/usb/Usb.h @@ -19,9 +19,9 @@ #include #include #include -#include #include #include +#include #define UEVENT_MSG_LEN 2048 // The type-c stack waits for 4.5 - 5.5 secs before declaring a port non-pd. @@ -88,6 +88,8 @@ 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 @@ -98,36 +100,6 @@ struct Usb : public BnUsb { int mUsbHubVendorCmdValue; int mUsbHubVendorCmdIndex; - // USB device state monitoring - struct usbDeviceState { - // Usb device state raw strings read from sysfs - std::vector states; - // Timestamps of when the usb device states were captured - std::vector timestamps; - int portResetCount; - }; - struct usbDeviceState mDeviceState; - // Map host device path name to usbDeviceState - std::map 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 cb; - }; - std::map mEpollEntries; - private: pthread_t mPoll; pthread_t mUsbHost; diff --git a/usb/usb/UsbDataSessionMonitor.cpp b/usb/usb/UsbDataSessionMonitor.cpp new file mode 100644 index 00000000..77defb30 --- /dev/null +++ b/usb/usb/UsbDataSessionMonitor.cpp @@ -0,0 +1,420 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 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 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 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 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 *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 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//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 new file mode 100644 index 00000000..596f378f --- /dev/null +++ b/usb/usb/UsbDataSessionMonitor.h @@ -0,0 +1,114 @@ +/* + * 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 +#include +#include +#include + +#include +#include +#include + +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 updatePortStatusCb); + ~UsbDataSessionMonitor(); + // Returns the compliance warnings detected in the current data session. + void getComplianceWarnings(const PortDataRole &role, std::vector *warnings); + + private: + struct usbDeviceState { + unique_fd fd; + std::string filePath; + std::string ueventRegex; + // Usb device states reported by state sysfs + std::vector states; + // Timestamps of when the usb device states were captured + std::vector 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 mWarningSet; + // Callback function to notify the caller when there's a change in compliance warnings. + std::function 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