diff options
author | Roman Stratiienko <roman.o.stratiienko@globallogic.com> | 2022-02-18 16:51:53 +0200 |
---|---|---|
committer | Roman Stratiienko <roman.o.stratiienko@globallogic.com> | 2022-02-18 17:16:00 +0200 |
commit | bd9731713b79f80b2fa1bf180b663649c9d357a5 (patch) | |
tree | 1256204708f87e61c547959ef2dd7e77d8499630 | |
parent | 2c63b3337380dd35ee0c658c05e27bcd89239b10 (diff) | |
download | drm_hwcomposer-bd9731713b79f80b2fa1bf180b663649c9d357a5.tar.gz |
drm_hwcomposer: Add test utility to listen for uevents
Dumping uevents is useful for debugging purposes.
1. Extract logic related to uevent socket into utils/UEvent.h class.
2. Use it by both UEventListener.cpp and tests/uevent_print.cpp.
Bump clang-tidy level of UEventListener.cpp to normal.
Signed-off-by: Roman Stratiienko <roman.o.stratiienko@globallogic.com>
-rw-r--r-- | .ci/Makefile | 7 | ||||
-rw-r--r-- | drm/UEventListener.cpp | 67 | ||||
-rw-r--r-- | drm/UEventListener.h | 4 | ||||
-rw-r--r-- | tests/Android.bp | 14 | ||||
-rw-r--r-- | tests/uevent_print.cpp | 25 | ||||
-rw-r--r-- | utils/UEvent.h | 85 |
6 files changed, 143 insertions, 59 deletions
diff --git a/.ci/Makefile b/.ci/Makefile index cadbde6..a0e4b73 100644 --- a/.ci/Makefile +++ b/.ci/Makefile @@ -26,7 +26,6 @@ TIDY_FILES_OVERRIDE := \ drm/DrmProperty.h:COARSE \ drm/DrmUnique.h:FINE \ drm/DrmProperty.cpp:COARSE \ - drm/UEventListener.cpp:COARSE \ drm/VSyncWorker.cpp:COARSE \ hwc2_device/DrmHwcTwo.cpp:COARSE \ hwc2_device/DrmHwcTwo.h:COARSE \ @@ -85,7 +84,7 @@ clean: # Build -BUILD_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/*' -path '*.cpp') +BUILD_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/test_include/*' -path '*.cpp') SKIP_FILES_path := $(foreach file,$(SKIP_FILES),$(SRC_DIR)/$(file)) BUILD_FILES := $(subst ./,,$(filter-out $(SKIP_FILES_path),$(BUILD_FILES_AUTO))) @@ -108,7 +107,7 @@ $(OUT_DIR)/%.d: $(SRC_DIR)/%.cpp $(CLANG) $(CXXARGS) $< -MM -MT $(OUT_DIR)/$(patsubst %.cpp,%.o,$<) -o $@ # TIDY -TIDY_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/*' \( -path '*.cpp' -o -path '*.h' \)) +TIDY_FILES_AUTO := $(shell find -L $(SRC_DIR) -not -path '*/\.*' -not -path '*/tests/test_include/*' \( -path '*.cpp' -o -path '*.h' \)) TIDY_FILES_AUTO_filtered := $(filter-out $(SKIP_FILES_path),$(TIDY_FILES_AUTO)) @@ -145,7 +144,7 @@ $$(_TARG): _TARG := $$(_TARG) $$(_TARG): TIDY_ARGS := $$(TIDY_ARGS) $$(_TARG): $$(_DEP) mkdir -p $$(dir $$(_TARG)) - $$(CLANG_TIDY) $$(_DEP) $$(TIDY_ARGS) -- -x c++ $$(CXXARGS) + $$(CLANG_TIDY) $$(_DEP) $$(TIDY_ARGS) -- -x c++ $$(CXXARGS) -Wno-pragma-once-outside-header touch $$(_TARG) endef diff --git a/drm/UEventListener.cpp b/drm/UEventListener.cpp index 8d33ad2..b56b8e1 100644 --- a/drm/UEventListener.cpp +++ b/drm/UEventListener.cpp @@ -18,82 +18,43 @@ #include "UEventListener.h" -#include <linux/netlink.h> -#include <sys/socket.h> -#include <xf86drm.h> - -#include <cassert> #include <cerrno> -#include <cstring> #include "utils/log.h" -/* Originally defined in system/core/libsystem/include/system/graphics.h */ -#define HAL_PRIORITY_URGENT_DISPLAY (-8) +/* Originally defined in system/core/libsystem/include/system/graphics.h as + * #define HAL_PRIORITY_URGENT_DISPLAY (-8)*/ +constexpr int kHalPriorityUrgentDisplay = -8; namespace android { UEventListener::UEventListener() - : Worker("uevent-listener", HAL_PRIORITY_URGENT_DISPLAY){}; + : Worker("uevent-listener", kHalPriorityUrgentDisplay){}; int UEventListener::Init() { - uevent_fd_ = UniqueFd( - socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)); - if (!uevent_fd_) { - // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme - ALOGE("Failed to open uevent socket: %s", strerror(errno)); - return -errno; - } - - struct sockaddr_nl addr {}; - addr.nl_family = AF_NETLINK; - addr.nl_pid = 0; - addr.nl_groups = 0xFFFFFFFF; - - int ret = bind(uevent_fd_.Get(), (struct sockaddr *)&addr, sizeof(addr)); - if (ret) { - // NOLINTNEXTLINE(concurrency-mt-unsafe): Fixme - ALOGE("Failed to bind uevent socket: %s", strerror(errno)); - return -errno; + uevent_ = UEvent::CreateInstance(); + if (!uevent_) { + return -ENODEV; } return InitWorker(); } void UEventListener::Routine() { - char buffer[1024]; - ssize_t ret = 0; - while (true) { - ret = read(uevent_fd_.Get(), &buffer, sizeof(buffer)); - if (ret == 0) - return; + auto uevent_str = uevent_->ReadNext(); - if (ret < 0) { - ALOGE("Got error reading uevent %zd", ret); - return; - } - - if (!hotplug_handler_) + if (!hotplug_handler_ || !uevent_str) continue; - bool drm_event = false; - bool hotplug_event = false; - for (uint32_t i = 0; (ssize_t)i < ret;) { - char *event = buffer + i; - if (strcmp(event, "DEVTYPE=drm_minor") != 0) - drm_event = true; - else if (strcmp(event, "HOTPLUG=1") != 0) - hotplug_event = true; - - i += strlen(event) + 1; - } + bool drm_event = uevent_str->find("DEVTYPE=drm_minor") != std::string::npos; + bool hotplug_event = uevent_str->find("HOTPLUG=1") != std::string::npos; - if (drm_event && hotplug_event && hotplug_handler_) { - constexpr useconds_t delay_after_uevent_us = 200000; + if (drm_event && hotplug_event) { + constexpr useconds_t kDelayAfterUeventUs = 200000; /* We need some delay to ensure DrmConnector::UpdateModes() will query * correct modes list, otherwise at least RPI4 board may report 0 modes */ - usleep(delay_after_uevent_us); + usleep(kDelayAfterUeventUs); hotplug_handler_(); } } diff --git a/drm/UEventListener.h b/drm/UEventListener.h index 0724443..c8b8582 100644 --- a/drm/UEventListener.h +++ b/drm/UEventListener.h @@ -19,7 +19,7 @@ #include <functional> -#include "utils/UniqueFd.h" +#include "utils/UEvent.h" #include "utils/Worker.h" namespace android { @@ -39,7 +39,7 @@ class UEventListener : public Worker { void Routine() override; private: - UniqueFd uevent_fd_; + std::unique_ptr<UEvent> uevent_; std::function<void()> hotplug_handler_; }; diff --git a/tests/Android.bp b/tests/Android.bp index 56f8c4f..e56ff5c 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -33,3 +33,17 @@ cc_test { "external/drm_hwcomposer/include", ], } + +// Tool for listening and dumping uevents +cc_test { + name: "hwc-drm-uevent-print", + + srcs: ["uevent_print.cpp"], + + vendor: true, + header_libs: ["libhardware_headers"], + shared_libs: ["liblog"], + include_dirs: [ + "external/drm_hwcomposer", + ], +} diff --git a/tests/uevent_print.cpp b/tests/uevent_print.cpp new file mode 100644 index 0000000..6ffbbfb --- /dev/null +++ b/tests/uevent_print.cpp @@ -0,0 +1,25 @@ +// SPDX-License-Identifier: Apache-2.0 + +#include <iostream> + +#include "utils/UEvent.h" + +int main() { + auto uevent = android::UEvent::CreateInstance(); + if (!uevent) { + std::cout << "Can't initialize UEvent class" << std::endl; + return -ENODEV; + } + + int number = 0; + for (;;) { + auto msg = uevent->ReadNext(); + if (!msg) { + continue; + } + + std::cout << "New event #" << number++ << std::endl + << *msg << std::endl + << std::endl; + } +} diff --git a/utils/UEvent.h b/utils/UEvent.h new file mode 100644 index 0000000..17b3cab --- /dev/null +++ b/utils/UEvent.h @@ -0,0 +1,85 @@ +/* + * Copyright (C) 2022 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 <linux/netlink.h> +#include <sys/socket.h> + +#include <cerrno> +#include <memory> +#include <optional> +#include <string> + +#include "UniqueFd.h" +#include "log.h" + +namespace android { + +class UEvent { + public: + static auto CreateInstance() -> std::unique_ptr<UEvent> { + auto fd = UniqueFd( + socket(PF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_KOBJECT_UEVENT)); + + if (!fd) { + ALOGE("Failed to open uevent socket: errno=%i", errno); + return {}; + } + + struct sockaddr_nl addr {}; + addr.nl_family = AF_NETLINK; + addr.nl_pid = 0; + addr.nl_groups = UINT32_MAX; + + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-cstyle-cast) + int ret = bind(fd.Get(), (struct sockaddr *)&addr, sizeof(addr)); + if (ret != 0) { + ALOGE("Failed to bind uevent socket: errno=%i", errno); + return {}; + } + + return std::unique_ptr<UEvent>(new UEvent(fd)); + } + + auto ReadNext() -> std::optional<std::string> { + constexpr int kUEventBufferSize = 1024; + char buffer[kUEventBufferSize]; + ssize_t ret = 0; + ret = read(fd_.Get(), &buffer, sizeof(buffer)); + if (ret == 0) + return {}; + + if (ret < 0) { + ALOGE("Got error reading uevent %zd", ret); + return {}; + } + + for (int i = 0; i < ret - 1; i++) { + if (buffer[i] == '\0') { + buffer[i] = '\n'; + } + } + + return std::string(buffer); + } + + private: + explicit UEvent(UniqueFd &fd) : fd_(std::move(fd)){}; + UniqueFd fd_; +}; + +} // namespace android |