Skip to content

feat: enable the configuration for device blacklist.#463

Merged
deepin-bot[bot] merged 1 commit intolinuxdeepin:release/eaglefrom
lichaofan2008:release/eagle
Mar 19, 2026
Merged

feat: enable the configuration for device blacklist.#463
deepin-bot[bot] merged 1 commit intolinuxdeepin:release/eaglefrom
lichaofan2008:release/eagle

Conversation

@lichaofan2008
Copy link
Contributor

@lichaofan2008 lichaofan2008 commented Mar 17, 2026

Use the DConfig mechanism to enable the configuration for device blacklist.
使用DConfig机制,开发设备黑名单功能,处在黑名单中的设备不会被应用显示。如果现有设备全部在黑名单中,则会有一个默认设备用于预览。
代码来自xiwo分支。

Bug: https://pms.uniontech.com/bug-view-349401.html

Summary by Sourcery

Introduce configurable camera device blacklisting and ensure only valid devices are used for preview and UI controls.

New Features:

  • Load a camera device blacklist from DConfig at startup and store it centrally in DataManager.
  • Filter camera devices against the configured blacklist when selecting the active preview device and when deciding whether to show the camera switch button.

Enhancements:

  • Add helper logic to select the first valid camera device when the configured device is missing, invalid, or blacklisted.
  • Respect per-device validity flags across device list usages to avoid presenting invalid or blacklisted devices and to improve device iteration efficiency.
  • Improve error handling and logging when reading the camera configuration file or obtaining the device list.

@sourcery-ai
Copy link

sourcery-ai bot commented Mar 17, 2026

Reviewer's Guide

Implements a device blacklist via DConfig and threads it through startup, device enumeration, and UI logic so that blacklisted or invalid camera devices are skipped and fall back to a valid/default device while also controlling when the camera-switch button is shown.

Sequence diagram for startup and device blacklist application

sequenceDiagram
    participant main_cpp as main
    participant DConfig as DConfig
    participant DataManager as DataManager
    participant VideoWidget as videowidget
    participant V4L2 as v4l2core

    main_cpp->>DConfig: create dconfig
    DConfig-->>main_cpp: dconfig object
    main_cpp->>DConfig: isValid()
    DConfig-->>main_cpp: bool
    main_cpp->>DConfig: keyList()
    DConfig-->>main_cpp: keys
    main_cpp->>DConfig: value(deviceBlacklist)
    DConfig-->>main_cpp: QStringList blacklist
    main_cpp->>DataManager: setDeviceBlacklist(blacklist)

    main_cpp->>VideoWidget: construct videowidget
    VideoWidget->>VideoWidget: delayInit()
    VideoWidget->>V4L2: v4l2core_get_device_index(configDevice)
    V4L2-->>VideoWidget: idx
    alt config device empty or idx < 0
        VideoWidget->>VideoWidget: getFirstValidDevice()
        VideoWidget->>V4L2: get_device_list()
        V4L2-->>VideoWidget: v4l2_device_list_t
        loop each device
            VideoWidget->>DataManager: isDeviceValid(vid,pid,name)
            DataManager-->>VideoWidget: bool
        end
        VideoWidget->>V4L2: switchCamera(validDevice)
    else config device found
        VideoWidget->>V4L2: get_device_list()
        V4L2-->>VideoWidget: v4l2_device_list_t
        VideoWidget->>DataManager: isDeviceValid(vid,pid,name)
        DataManager-->>VideoWidget: bool
        alt device blacklisted
            VideoWidget->>VideoWidget: getFirstValidDevice()
            VideoWidget->>V4L2: switchCamera(validDevice)
        else device valid
            VideoWidget->>V4L2: switchCamera(configDevice)
        end
    end
Loading

Class diagram for new device blacklist handling

classDiagram
    class DataManager {
        -static DataManager *m_dataManager
        -QStringList m_deviceBlacklist
        -bool m_isPreviewNoDelay
        -bool m_enableUsbGroup
        -bool m_enable8kPreview
        +static DataManager* instance()
        +bool isEnable8kPreview() const
        +void setDeviceBlacklist(QStringList blacklist)
        +bool isDeviceValid(QString vid, QString pid, QString name)
    }

    class videowidget {
        +void delayInit()
        +QString getSaveFilePrefix()
        +QString getFirstValidDevice()
        +MajorImageProcessingThread *m_imgPrcThread
        +AudioProcessingThread *m_audPrcThread
    }

    class CMainWindow {
        -bool m_bSwitchCameraShowEnable
        +void setSelBtnShow()
    }

    class Camera {
        -std::vector<QString> m_cameraDevList
        +void refreshCamDevList()
        +int parseConfig()
    }

    class v4l2_device_list_t {
        +int num_devices
        +v4l2_dev_sys_data_t *list_devices
    }

    class v4l2_dev_sys_data_t {
        +int vendor
        +int product
        +int valid
        +QString name
        +QString device
    }

    class main_cpp {
        +int main(int argc, char *argv[])
    }

    main_cpp --> DataManager : setDeviceBlacklist
    videowidget --> DataManager : isDeviceValid
    videowidget --> v4l2_device_list_t : get_device_list
    videowidget --> v4l2_dev_sys_data_t : read vendor,product,valid,name,device
    CMainWindow --> v4l2_device_list_t : get_device_list
    CMainWindow --> v4l2_dev_sys_data_t : read/write valid, read vendor,product,name
    CMainWindow --> DataManager : isDeviceValid
    Camera --> v4l2_device_list_t : get_device_list
    Camera --> v4l2_dev_sys_data_t : read valid,device
    Camera --> DataManager : (indirect filtering via valid flag)
Loading

File-Level Changes

Change Details Files
Validate the configured camera device against the blacklist and fall back to the first valid device when necessary during video initialization.
  • Replace direct use of the configured device with logic that resolves its index via v4l2core_get_device_index and checks for emptiness or invalid index
  • If the configured device is missing or invalid, compute the first valid device using a new helper and switch to it, otherwise continue with normal switchCamera behavior
  • When the device list retrieval fails or returns inconsistent data, log warnings and fall back to the default switchCamera logic
  • For a valid index, derive VID/PID, normalize them to 4-digit hex, and use DataManager::isDeviceValid to skip blacklisted devices and fall back to the first valid device if needed
src/src/videowidget.cpp
Provide a helper to retrieve the first non-blacklisted valid camera device from the v4l2 device list.
  • Add getFirstValidDevice method that obtains the device list and safely handles null list or entries with warnings and empty-string return
  • Iterate over devices, skipping those with valid flag unset, and compute normalized VID/PID values for each device
  • Use DataManager::isDeviceValid to find the first device not in the blacklist and return its device node, logging the selection or the absence of any valid device
src/src/videowidget.cpp
src/src/videowidget.h
Filter the camera list and camera-switch button visibility based on the blacklist, updating the v4l2 device valid flag accordingly.
  • In CMainWindow::setSelBtnShow, fetch the device list with null checks and early returns on failure, logging warnings as needed
  • Traverse devices, skipping already invalid ones, and call DataManager::isDeviceValid to determine whether each device should remain available
  • When a device is blacklisted, log it and set its valid flag to 0 as the sole write site, then count remaining valid devices and hide the switch button when there is one or zero valid devices
src/src/mainwindow.cpp
Ensure camera device enumeration and configuration parsing respect the blacklist and improve error logging.
  • Update Camera::refreshCamDevList to handle a null device list safely and log a warning before returning
  • Skip devices whose valid flag is unset when populating m_cameraDevList to avoid adding blacklisted devices
  • Fix parseConfig error logging to print the correct file path variable when fopen fails
src/src/camera.cpp
Introduce DataManager-managed device blacklist configuration and wiring from DConfig into runtime checks.
  • Add a QStringList member to DataManager to hold the device blacklist and a setter to update it
  • Expose isDeviceValid to test a device (VID, PID, name) against the blacklist by composing and looking up a single key
  • In main, read the deviceBlacklist key from DConfig when available, log its contents, and propagate it into DataManager via setDeviceBlacklist
src/src/basepub/datamanager.h
src/main.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 2 issues, and left some high level feedback:

  • The logic for walking v4l2_device_list_t, checking valid, and applying DataManager::isDeviceValid is duplicated in several places (videowidget::delayInit, videowidget::getFirstValidDevice, CMainWindow::setSelBtnShow, Camera::refreshCamDevList); consider extracting a shared helper to produce a filtered list of valid devices so the blacklist behavior stays consistent and is easier to maintain.
  • In CMainWindow::setSelBtnShow, when validNum <= 1 you return early without updating m_bSwitchCameraShowEnable or hiding the switch button, which could leave a stale visible switch button if the number of valid devices drops at runtime; it may be safer to explicitly reset/hide the button in this branch.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The logic for walking `v4l2_device_list_t`, checking `valid`, and applying `DataManager::isDeviceValid` is duplicated in several places (`videowidget::delayInit`, `videowidget::getFirstValidDevice`, `CMainWindow::setSelBtnShow`, `Camera::refreshCamDevList`); consider extracting a shared helper to produce a filtered list of valid devices so the blacklist behavior stays consistent and is easier to maintain.
- In `CMainWindow::setSelBtnShow`, when `validNum <= 1` you return early without updating `m_bSwitchCameraShowEnable` or hiding the switch button, which could leave a stale visible switch button if the number of valid devices drops at runtime; it may be safer to explicitly reset/hide the button in this branch.

## Individual Comments

### Comment 1
<location path="src/src/camera.cpp" line_range="159-166" />
<code_context>
     m_cameraDevList.clear();

     v4l2_device_list_t *devlist = get_device_list();
-    for (int i = 0; i < devlist->num_devices; i++)
+    if (!devlist) {
+        qWarning() << __func__ << "get device list FAILED!";
+        return;
+    }
+
+    for (int i = 0; i < devlist->num_devices; i++) {
+        // 有黑名单的存在,跳过无效的设备
+        if (!devlist->list_devices[i].valid) {
+            continue;
</code_context>
<issue_to_address>
**issue (bug_risk):** Add a null check for `devlist->list_devices` before iterating, for consistency with other call sites.

Other call sites (e.g. `getFirstValidDevice`, `setSelBtnShow`) also guard `devlist->list_devices` before use. To avoid a possible null dereference from a partially initialized `v4l2_device_list_t`, please also check `devlist->list_devices` here:

```cpp
if (!devlist || !devlist->list_devices) {
    qWarning() << __func__ << "get device list FAILED!";
    return;
}
```
</issue_to_address>

### Comment 2
<location path="src/main.cpp" line_range="202-206" />
<code_context>
         set_enable_8k_preview(enable ? 1 : 0);
     }

+    if (dconfig && dconfig->isValid() && dconfig->keyList().contains("deviceBlacklist")) {
+        QStringList deviceBlacklist = dconfig->value("deviceBlacklist").toStringList();
+        qInfo() << "device blacklist:" << deviceBlacklist;
+        DataManager::instance()->setDeviceBlacklist(deviceBlacklist);
+    }
+
</code_context>
<issue_to_address>
**suggestion:** Validate the format of `deviceBlacklist` entries or log malformed entries to make misconfiguration easier to debug.

This relies on every `deviceBlacklist` entry matching the `vid,pid,name` format expected by `isDeviceValid`. Malformed entries (wrong component count, different separators) will just be ignored, making config issues hard to diagnose. Consider validating entries or logging a warning for malformed ones when loading the config.

```suggestion
    if (dconfig && dconfig->isValid() && dconfig->keyList().contains("deviceBlacklist")) {
        QStringList deviceBlacklist = dconfig->value("deviceBlacklist").toStringList();

        QStringList validDeviceBlacklist;
        for (const QString &entry : deviceBlacklist) {
            const QStringList parts = entry.split(',');

            // Expecting "vid,pid,name" format as required by isDeviceValid
            if (parts.size() != 3 || parts[0].trimmed().isEmpty() || parts[1].trimmed().isEmpty() || parts[2].trimmed().isEmpty()) {
                qWarning() << "Ignoring malformed deviceBlacklist entry:" << entry
                           << "- expected format: vid,pid,name";
                continue;
            }

            validDeviceBlacklist << entry;
        }

        qInfo() << "device blacklist (valid entries):" << validDeviceBlacklist;
        DataManager::instance()->setDeviceBlacklist(validDeviceBlacklist);
    }
```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@lichaofan2008 lichaofan2008 force-pushed the release/eagle branch 13 times, most recently from 210a1bc to 55d5c30 Compare March 19, 2026 02:00
Use the DConfig mechanism to enable the configuration for device blacklist.
使用DConfig机制,开发设备黑名单功能,处在黑名单中的设备不会被应用显示。如果现有设备全部在黑名单中,则会有一个默认设备用于预览。
代码来自xiwo分支。

Bug: https://pms.uniontech.com/bug-view-349401.html
@deepin-ci-robot
Copy link

deepin pr auto review

代码审查报告

总体评价

这次代码修改主要是为相机应用添加了设备黑名单功能,整体设计合理,实现较为完整。代码结构清晰,功能模块划分明确,但还有一些可以改进的地方。

具体分析

1. 设备黑名单功能实现

优点:

  • 在配置文件中添加了设备黑名单的配置项
  • 实现了黑名单的设置和验证逻辑
  • 提供了设备有效性检查接口

改进建议:

  • 黑名单存储在内存中,如果应用重启需要重新加载,可以考虑持久化存储
  • DataManager::setDeviceBlacklist 中,验证逻辑较为严格,但错误处理可以更友好,比如提供更详细的错误信息
  • 黑名单格式验证可以提取为单独的函数,提高代码复用性
// 建议添加更详细的错误信息
if (parts.size() != 3) {
    qWarning() << "Drop blacklist item(format error):" << item 
               << "Expected format: vid,pid,name";
    continue;
}

2. 设备管理相关改进

优点:

  • 添加了有效设备列表的管理
  • 实现了设备有效性检查机制
  • 使用读写锁保护共享数据

改进建议:

  • updateValidDevices 函数中,获取设备列表后应该检查返回值
  • 设备ID格式化函数可以添加参数控制是否补零
  • 设备有效性检查可以考虑添加缓存机制,避免频繁验证
// 建议添加设备列表有效性检查
if (!devList || !devList->list_devices || devList->num_devices <= 0) {
    qWarning() << __func__ << "Invalid device list!";
    return;
}

3. 设备切换逻辑优化

优点:

  • 改进了设备切换逻辑,考虑了黑名单
  • 优化了设备分组处理
  • 添加了设备有效性检查

改进建议:

  • 设备切换逻辑较为复杂,可以考虑拆分为更小的函数
  • onChangeDev 中,设备切换失败时应该有回退机制
  • 可以添加设备切换超时处理
// 建议添加设备切换超时处理
bool videowidget::switchCameraWithTimeout(const char *device, const char *name, int timeoutMs) {
    QFuture<bool> future = QtConcurrent::run([this, device, name]() {
        return switchCamera(device, name);
    });
    
    if (future.waitFor(timeoutMs)) {
        return future.result();
    }
    return false;
}

4. 线程安全性

优点:

  • 使用了读写锁保护共享数据
  • 设备列表更新考虑了线程安全

改进建议:

  • 读写锁的范围可以适当缩小,减少锁的持有时间
  • 可以考虑使用原子操作替代部分锁机制
  • 设备列表的更新可以采用发布-订阅模式,减少锁的使用
// 建议缩小锁的范围
void videowidget::updateValidDevices() {
    // 先获取设备数据
    v4l2_device_list_t *devList = get_device_list();
    if (!devList) return;
    
    // 处理数据
    QVector<ValidDevice> newDevices;
    // ...处理逻辑...
    
    // 最后更新数据
    {
        QWriteLocker locker(&m_mutexValidDevices);
        m_validDevices = newDevices;
    }
}

5. 性能优化

优点:

  • 使用了读写锁提高并发性能
  • 设备列表更新只在必要时进行

改进建议:

  • 设备有效性检查可以考虑缓存结果
  • 设备列表更新可以采用增量更新,而不是全量更新
  • 可以添加设备状态缓存,减少重复查询
// 建议添加设备状态缓存
QMap<QString, DeviceStatus> m_deviceStatusCache;

void videowidget::updateDeviceStatus(const QString &device) {
    // 检查缓存是否过期
    if (m_deviceStatusCache.contains(device) && 
        !m_deviceStatusCache[device].isExpired()) {
        return;
    }
    
    // 更新设备状态
    DeviceStatus status = checkDeviceStatus(device);
    m_deviceStatusCache[device] = status;
}

6. 错误处理

优点:

  • 对设备黑名单格式进行了验证
  • 对设备有效性进行了检查

改进建议:

  • 错误处理可以更加统一,使用自定义异常类
  • 可以添加错误恢复机制
  • 日志记录可以更加详细,便于问题排查
// 建议使用自定义异常类
class DeviceException : public std::exception {
public:
    DeviceException(const QString &message, DeviceError error) 
        : m_message(message), m_error(error) {}
    
    const char *what() const noexcept override {
        return m_message.toStdString().c_str();
    }
    
    DeviceError error() const { return m_error; }
    
private:
    QString m_message;
    DeviceError m_error;
};

总结

这次代码修改整体质量较高,实现了设备黑名单功能,并优化了设备管理逻辑。主要改进方向包括:

  1. 增强错误处理和日志记录
  2. 优化性能,减少不必要的锁和重复计算
  3. 提高代码可维护性,拆分复杂函数
  4. 添加更多边界条件处理
  5. 考虑添加持久化存储

这些改进将有助于提高代码的健壮性、性能和可维护性。

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: lichaofan2008, max-lvs

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@lichaofan2008
Copy link
Contributor Author

/merge

@deepin-bot deepin-bot bot merged commit 183e017 into linuxdeepin:release/eagle Mar 19, 2026
22 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants