Commit bd973171 authored by Roman Stratiienko's avatar Roman Stratiienko
Browse files

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: default avatarRoman Stratiienko <roman.o.stratiienko@globallogic.com>
parent 2c63b333
Pipeline #512630 passed with stages
in 17 minutes
......@@ -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
......
......@@ -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_();
}
}
......
......@@ -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_;
};
......
......@@ -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",
],
}
// 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;
}
}
/*
* 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
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment