Skip to content

Power Vote 投票仲裁机制

1. 模块定位与核心价值

1.1 问题域

在华为 MATE X5 电源管理系统中,同一个参数可能被多个模块同时控制,这会导致冲突和混乱:

典型冲突场景:

充电电流限制问题:
├─ 温度管理模块:温度 > 45°C,限制充电电流 ≤ 2000mA
├─ 电池健康模块:循环次数 > 500,限制充电电流 ≤ 1500mA  
├─ 用户设置模块:用户设置省电模式,限制充电电流 ≤ 1000mA
├─ USB 识别模块:识别为 SDP,限制充电电流 ≤ 500mA
└─ 直充模块:     检测到快充适配器,需要充电电流 = 5000mA

❌ 问题:哪个模块的设置应该生效?如何协调?

传统解决方案的缺陷:

  • 硬编码优先级:修改逻辑需要改代码
  • 全局变量竞争:多线程访问不安全
  • 难以调试:无法追溯最终值由谁决定

1.2 Power Vote 解决方案

核心思想: 将参数控制权转化为"投票机制"

投票箱(Vote Object): "charging_current"
类型:取最小值(SET_MIN)

投票过程:
┌──────────────────────────────────────────────┐
│ 客户端投票                                    │
├──────────────────────────────────────────────┤
│ "temp_mgr"       enabled=true   value=2000   │
│ "bat_health"     enabled=true   value=1500   │
│ "user_settings"  enabled=true   value=1000   │
│ "usb_detect"     enabled=true   value=500    │ ← 最小值
│ "direct_charge"  enabled=false  value=5000   │ (未使能)
└──────────────────────────────────────────────┘

            仲裁结果:500mA
         (由 "usb_detect" 决定)

        回调函数:set_charging_current(500)

1.3 架构设计

┌─────────────────────────────────────────────────────┐
│  Power Vote 模块 (cc_common_module/power_vote)      │
│                                                      │
│  ┌────────────────────────────────────────────┐    │
│  │  全局投票对象链表 (g_power_vote_list)      │    │
│  │  ├─ Vote Object 1: "charging_current"      │    │
│  │  ├─ Vote Object 2: "charging_voltage"      │    │
│  │  ├─ Vote Object 3: "input_suspend"         │    │
│  │  └─ Vote Object N: ...                     │    │
│  └────────────────────────────────────────────┘    │
│                                                      │
│  ┌────────────────────────────────────────────┐    │
│  │  投票类型(仲裁策略)                       │    │
│  │  ├─ POWER_VOTE_SET_MIN  (取最小值)       │    │
│  │  ├─ POWER_VOTE_SET_MAX  (取最大值)       │    │
│  │  └─ POWER_VOTE_SET_ANY  (任意使能即true) │    │
│  └────────────────────────────────────────────┘    │
│                                                      │
│  ┌────────────────────────────────────────────┐    │
│  │  调试接口                                   │    │
│  │  /sys/kernel/debug/hw_power/power_vote/   │    │
│  │      └─ object  (查看所有投票状态)         │    │
│  └────────────────────────────────────────────┘    │
└─────────────────────────────────────────────────────┘

2. 核心数据结构

2.1 投票对象(Vote Object)

c
struct power_vote_object {
    const char *name;                       // 投票对象名称(如 "charging_current")
    struct list_head list;                  // 链表节点(挂载到全局链表)
    struct mutex lock;                      // 互斥锁(保护并发访问)
    int type;                               // 投票类型(SET_MIN/SET_MAX/SET_ANY)
    bool voted_on;                          // 是否已执行过投票
    int eff_client_id;                      // 当前生效的客户端 ID
    int eff_result;                         // 当前生效的投票结果
    int override_result;                    // 覆盖结果(-1 表示无覆盖)
    struct power_vote_client_data clients[POWER_VOTE_MAX_CLIENTS]; // 客户端数组(最多32个)
    void *data;                             // 回调函数私有数据
    int (*cb)(struct power_vote_object *obj, void *data, 
              int result, const char *client_str); // 结果变化时的回调函数
};

字段说明:

  • name:投票对象的唯一标识符
  • type:仲裁策略(决定如何从多个投票中选出最终结果)
  • eff_result:当前生效的值(仲裁后的最终结果)
  • override_result:强制覆盖值(用于调试或特殊场景,-1表示不覆盖)
  • cb:当仲裁结果变化时调用的回调函数

2.2 客户端数据(Client Data)

c
struct power_vote_client_data {
    char *name;       // 客户端名称(如 "temp_mgr", "usb_detect")
    bool enabled;     // 是否使能(只有使能的投票才参与仲裁)
    int value;        // 投票值
};

客户端管理:

  • 每个投票对象最多支持 32 个客户端(POWER_VOTE_MAX_CLIENTS
  • 客户端动态注册(首次投票时自动创建)
  • 客户端名称不可重复

2.3 投票类型枚举

c
enum power_vote_type {
    POWER_VOTE_SET_MIN,   // 取所有使能投票中的最小值
    POWER_VOTE_SET_MAX,   // 取所有使能投票中的最大值
    POWER_VOTE_SET_ANY,   // 任意一个使能即为 true(用于开关控制)
};

3. 三种仲裁策略详解

3.1 SET_MIN - 取最小值

使用场景: 限制类参数(充电电流、输入电压等)

仲裁逻辑:

c
static void power_vote_set_min(struct power_vote_object *obj,
    int client_id, int *eff_result, int *eff_id)
{
    int i;
    
    *eff_result = INT_MAX;  // 初始化为最大整数
    *eff_id = -1;
    
    // 遍历所有客户端
    for (i = 0; i < POWER_VOTE_MAX_CLIENTS; i++) {
        if (!obj->clients[i].name)
            break;
        
        // 只考虑使能的投票
        if (!obj->clients[i].enabled)
            continue;
        
        // 更新最小值
        if (*eff_result > obj->clients[i].value) {
            *eff_result = obj->clients[i].value;
            *eff_id = i;
        }
    }
    
    // 如果没有使能的投票,返回 -1
    if (*eff_id == -1)
        *eff_result = -1;
}

应用示例:充电电流限制

c
// 创建投票对象
power_vote_create_object("fcc_votable", 
                         POWER_VOTE_SET_MIN, 
                         fcc_callback, 
                         NULL);

// 各模块投票
power_vote_set("fcc_votable", "THERMAL",      true, 2000); // 温度限制2A
power_vote_set("fcc_votable", "USER_LIMIT",   true, 1500); // 用户限制1.5A
power_vote_set("fcc_votable", "USB_ICL",      true, 500);  // USB限制500mA ← 最小
power_vote_set("fcc_votable", "BATTERY_FULL", false, 0);   // 未使能,忽略

// 仲裁结果:500mA(由 USB_ICL 决定)

3.2 SET_MAX - 取最大值

使用场景: 优先级选择(充电优先级、功率等级等)

仲裁逻辑:

c
static void power_vote_set_max(struct power_vote_object *obj,
    int client_id, int *eff_result, int *eff_id)
{
    int i;
    
    *eff_result = INT_MIN;  // 初始化为最小整数
    *eff_id = -1;
    
    for (i = 0; i < POWER_VOTE_MAX_CLIENTS; i++) {
        if (!obj->clients[i].name)
            break;
        
        if (!obj->clients[i].enabled)
            continue;
        
        // 更新最大值
        if (*eff_result < obj->clients[i].value) {
            *eff_result = obj->clients[i].value;
            *eff_id = i;
        }
    }
    
    if (*eff_id == -1)
        *eff_result = -1;
}

应用示例:电源模式选择

c
// 创建投票对象
power_vote_create_object("power_mode", 
                         POWER_VOTE_SET_MAX, 
                         mode_callback, 
                         NULL);

// 各模块投票(值越大优先级越高)
power_vote_set("power_mode", "LOW_POWER",    true, 1);  // 省电模式
power_vote_set("power_mode", "BALANCED",     true, 2);  // 均衡模式
power_vote_set("power_mode", "PERFORMANCE",  true, 3);  // 性能模式 ← 最大
power_vote_set("power_mode", "ULTRA_SAVE",   false, 0); // 未使能

// 仲裁结果:3(性能模式生效)

3.3 SET_ANY - 任意使能即为真

使用场景: 开关控制(充电使能、输入暂停等)

仲裁逻辑:

c
static void power_vote_set_any(struct power_vote_object *obj,
    int client_id, int *eff_result, int *eff_id)
{
    int i;
    
    *eff_result = 0;  // 初始化为 false
    *eff_id = client_id;
    
    // 统计使能的客户端数量
    for (i = 0; i < POWER_VOTE_MAX_CLIENTS; i++) {
        if (!obj->clients[i].name)
            break;
        
        if (obj->clients[i].enabled)
            *eff_result += 1;
    }
    
    // 只要有任意客户端使能,结果就为 true
    if (*eff_result)
        *eff_result = 1;  // true
}

应用示例:输入暂停控制

c
// 创建投票对象
power_vote_create_object("usb_suspend", 
                         POWER_VOTE_SET_ANY, 
                         suspend_callback, 
                         NULL);

// 各模块投票(value值被忽略,仅看enabled)
power_vote_set("usb_suspend", "OTG_MODE",     true, 0);  // OTG模式暂停充电
power_vote_set("usb_suspend", "OVER_TEMP",    false, 0); // 温度正常,不暂停
power_vote_set("usb_suspend", "USER_DISABLE", false, 0); // 用户未禁用

// 仲裁结果:true(因为 OTG_MODE enabled=true)
// 只要有一个客户端 enabled=true,结果就是 true

4. 核心 API 详解

4.1 创建投票对象

c
int power_vote_create_object(const char *name,
    int vote_type, power_vote_cb cb, void *data)

参数说明:

  • name:投票对象名称(唯一标识符)
  • vote_type:仲裁类型(SET_MIN/SET_MAX/SET_ANY)
  • cb:结果变化时的回调函数
  • data:回调函数的私有数据指针

回调函数原型:

c
int callback(struct power_vote_object *obj, 
             void *data, 
             int result, 
             const char *client_str)
{
    // obj: 投票对象指针
    // data: 创建时传入的私有数据
    // result: 仲裁后的结果值
    // client_str: 决定结果的客户端名称
    
    hwlog_info("New result: %d from %s\n", result, client_str);
    
    // 实际执行参数设置
    set_hardware_register(result);
    
    return 0;  // 成功返回0,失败返回负值
}

使用示例:

c
static int fcc_callback(struct power_vote_object *obj, 
                        void *data, 
                        int result, 
                        const char *client_str)
{
    struct charger_dev *chg_dev = (struct charger_dev *)data;
    
    hwlog_info("Set FCC to %d mA by %s\n", result, client_str);
    
    return charger_set_current(chg_dev, result);
}

static int __init charger_init(void)
{
    struct charger_dev *chg_dev = get_charger_device();
    
    // 创建充电电流投票对象
    power_vote_create_object("FCC", 
                             POWER_VOTE_SET_MIN, 
                             fcc_callback, 
                             chg_dev);
    
    return 0;
}

4.2 投票(设置值)

c
int power_vote_set(const char *name,
    const char *client_name, bool enabled, int value)

参数说明:

  • name:投票对象名称
  • client_name:客户端名称(自动注册,无需预先创建)
  • enabled:是否使能(false时不参与仲裁)
  • value:投票值

工作流程:

1. 查找投票对象

2. 获取/创建客户端 ID

3. 检查投票是否相同(去重优化)

4. 执行仲裁(根据type选择策略)

5. 如果结果变化,调用回调函数

6. 返回结果

使用示例:

c
// 温度管理模块
void thermal_monitor_work(void)
{
    int temp = get_battery_temp();
    
    if (temp > 45) {
        // 温度过高,限制电流为 1500mA
        power_vote_set("FCC", "THERMAL", true, 1500);
    } else {
        // 温度正常,取消限制
        power_vote_set("FCC", "THERMAL", false, 0);
    }
}

// USB 识别模块
void usb_type_changed(int type)
{
    switch (type) {
    case USB_SDP:  // 标准下游端口
        power_vote_set("FCC", "USB_ICL", true, 500);
        break;
    case USB_DCP:  // 专用充电端口
        power_vote_set("FCC", "USB_ICL", true, 2000);
        break;
    case USB_CDP:  // 充电下游端口
        power_vote_set("FCC", "USB_ICL", true, 1500);
        break;
    }
}

4.3 强制覆盖

c
int power_vote_set_override(const char *name,
    const char *client_name, bool enabled, int value)

功能: 忽略所有其他投票,强制使用指定值(用于调试或紧急场景)

使用示例:

c
// 调试场景:强制设置充电电流为 3000mA
power_vote_set_override("FCC", "DEBUG", true, 3000);

// 恢复正常投票机制
power_vote_set_override("FCC", "DEBUG", false, 0);

4.4 查询接口

c
// 查询客户端是否使能
bool power_vote_is_client_enabled_locked(const char *name,
    const char *client_name, bool lock_flag);

// 查询客户端投票值
int power_vote_get_client_value_locked(const char *name,
    const char *client_name, bool lock_flag);

// 查询当前生效结果
int power_vote_get_effective_result_locked(const char *name, 
    bool lock_flag);

lock_flag 参数说明:

  • true:内部会加锁(线程安全)
  • false:调用者已持有锁(避免死锁)

5. 典型应用场景

5.1 充电电流动态调整

场景: 多个因素同时影响充电电流

c
// 初始化
static int charger_fcc_callback(struct power_vote_object *obj, 
                                void *data, int result, const char *client)
{
    hwlog_info("Set charging current to %d mA (by %s)\n", result, client);
    return charger_ic_set_current(result);
}

static void charger_init(void)
{
    power_vote_create_object("FCC_VOTABLE", 
                             POWER_VOTE_SET_MIN, 
                             charger_fcc_callback, 
                             NULL);
}

// 温度管理投票
void thermal_work(void)
{
    int temp = get_battery_temp();
    
    if (temp < 10) {
        // 低温限制 500mA
        power_vote_set("FCC_VOTABLE", "THERMAL", true, 500);
    } else if (temp > 45) {
        // 高温限制 1000mA
        power_vote_set("FCC_VOTABLE", "THERMAL", true, 1000);
    } else {
        // 正常温度不限制
        power_vote_set("FCC_VOTABLE", "THERMAL", false, 0);
    }
}

// 电池健康投票
void battery_health_check(void)
{
    int cycle_count = get_battery_cycle();
    
    if (cycle_count > 500) {
        // 老化电池限制 1500mA
        power_vote_set("FCC_VOTABLE", "BATTERY_AGE", true, 1500);
    } else {
        power_vote_set("FCC_VOTABLE", "BATTERY_AGE", false, 0);
    }
}

// USB 识别投票
void usb_type_detect(int type)
{
    if (type == USB_SDP) {
        power_vote_set("FCC_VOTABLE", "USB_TYPE", true, 500);
    } else if (type == USB_DCP) {
        power_vote_set("FCC_VOTABLE", "USB_TYPE", true, 2000);
    }
}

// 用户设置投票
void user_limit_setting(bool enabled, int limit)
{
    power_vote_set("FCC_VOTABLE", "USER", enabled, limit);
}

仲裁过程:

时刻 T1:
  USB_TYPE:    enabled=true,  value=2000  (USB DCP)
  THERMAL:     enabled=false, value=0     (温度正常)
  BATTERY_AGE: enabled=false, value=0     (新电池)
  USER:        enabled=false, value=0     (用户未限制)
  → 仲裁结果: 2000mA (由 USB_TYPE 决定)

时刻 T2:(温度升高到 46°C)
  USB_TYPE:    enabled=true,  value=2000
  THERMAL:     enabled=true,  value=1000  ← 新增限制
  BATTERY_AGE: enabled=false, value=0
  USER:        enabled=false, value=0
  → 仲裁结果: 1000mA (由 THERMAL 决定,最小值)

时刻 T3:(用户开启省电模式)
  USB_TYPE:    enabled=true,  value=2000
  THERMAL:     enabled=true,  value=1000
  BATTERY_AGE: enabled=false, value=0
  USER:        enabled=true,  value=500   ← 新增限制
  → 仲裁结果: 500mA (由 USER 决定,最小值)

5.2 输入暂停控制

场景: 多个条件触发输入暂停

c
// 初始化
static int suspend_callback(struct power_vote_object *obj, 
                            void *data, int result, const char *client)
{
    hwlog_info("USB suspend: %s (by %s)\n", 
               result ? "SUSPEND" : "RESUME", client);
    return usb_set_suspend(result);
}

static void suspend_init(void)
{
    power_vote_create_object("USB_SUSPEND", 
                             POWER_VOTE_SET_ANY,  // 任意一个使能即暂停
                             suspend_callback, 
                             NULL);
}

// OTG 模式
void otg_mode_changed(bool otg_enabled)
{
    // OTG 模式下必须暂停输入
    power_vote_set("USB_SUSPEND", "OTG", otg_enabled, 0);
}

// 温度保护
void temp_protect_check(void)
{
    int temp = get_battery_temp();
    
    // 温度过高暂停充电
    power_vote_set("USB_SUSPEND", "TEMP_PROTECT", temp > 60, 0);
}

// 工厂模式
void factory_mode_check(void)
{
    bool factory = is_factory_mode();
    
    // 工厂模式暂停充电
    power_vote_set("USB_SUSPEND", "FACTORY", factory, 0);
}

仲裁逻辑(SET_ANY):

只要有任意一个客户端 enabled=true,结果就是 true(暂停)

场景1:正常充电
  OTG:          enabled=false
  TEMP_PROTECT: enabled=false
  FACTORY:      enabled=false
  → 结果: false (不暂停,正常充电)

场景2:进入 OTG 模式
  OTG:          enabled=true  ← 触发暂停
  TEMP_PROTECT: enabled=false
  FACTORY:      enabled=false
  → 结果: true (暂停输入)

场景3:温度过高 + OTG
  OTG:          enabled=true
  TEMP_PROTECT: enabled=true  ← 两个都触发
  FACTORY:      enabled=false
  → 结果: true (仍然是暂停)

5.3 直充模式选择

场景: 根据多种条件选择最优充电模式

c
// 充电模式优先级(值越大优先级越高)
#define MODE_BUCK       0  // Buck 充电(5V)
#define MODE_FCP        1  // FCP 快充(9V)
#define MODE_LVC        2  // LVC 直充(1:1)
#define MODE_SC         3  // SC 直充(2:1)
#define MODE_SC4        4  // SC4 直充(4:1)

static int mode_callback(struct power_vote_object *obj, 
                         void *data, int result, const char *client)
{
    const char *mode_names[] = {"BUCK", "FCP", "LVC", "SC", "SC4"};
    
    hwlog_info("Switch to %s mode (by %s)\n", 
               mode_names[result], client);
    
    return switch_charging_mode(result);
}

static void mode_init(void)
{
    power_vote_create_object("CHARGE_MODE", 
                             POWER_VOTE_SET_MAX,  // 取最大值(最优模式)
                             mode_callback, 
                             NULL);
}

// 适配器检测
void adapter_detect_result(int adapter_cap)
{
    if (adapter_cap & ADAPTER_SC4_SUPPORT)
        power_vote_set("CHARGE_MODE", "ADAPTER", true, MODE_SC4);
    else if (adapter_cap & ADAPTER_SC_SUPPORT)
        power_vote_set("CHARGE_MODE", "ADAPTER", true, MODE_SC);
    else if (adapter_cap & ADAPTER_FCP_SUPPORT)
        power_vote_set("CHARGE_MODE", "ADAPTER", true, MODE_FCP);
    else
        power_vote_set("CHARGE_MODE", "ADAPTER", true, MODE_BUCK);
}

// 电池状态检查
void battery_status_check(void)
{
    int soc = get_battery_soc();
    int temp = get_battery_temp();
    
    // SOC > 90% 降级到 Buck
    if (soc > 90) {
        power_vote_set("CHARGE_MODE", "BATTERY_SOC", true, MODE_BUCK);
        return;
    }
    
    // 温度异常降级到 FCP
    if (temp < 10 || temp > 45) {
        power_vote_set("CHARGE_MODE", "BATTERY_TEMP", true, MODE_FCP);
        return;
    }
    
    // 正常状态不限制
    power_vote_set("CHARGE_MODE", "BATTERY_SOC", false, 0);
    power_vote_set("CHARGE_MODE", "BATTERY_TEMP", false, 0);
}

6. 调试与监控

6.1 Debugfs 接口

路径: /sys/kernel/debug/hw_power/power_vote/object

功能: 显示所有投票对象的状态

输出格式:

bash
$ cat /sys/kernel/debug/hw_power/power_vote/object

FCC_VOTABLE: type=Set_Min eff_result=500 eff_client_name=USB_TYPE eff_id=2
    THERMAL: enabled=0 value=0
    BATTERY_AGE: enabled=0 value=0
    USB_TYPE: enabled=1 value=500
    USER: enabled=0 value=0

USB_SUSPEND: type=Set_Any eff_result=1 eff_client_name=OTG eff_id=0
    OTG: enabled=1 value=0
    TEMP_PROTECT: enabled=0 value=0
    FACTORY: enabled=0 value=0

CHARGE_MODE: type=Set_Max eff_result=3 eff_client_name=ADAPTER eff_id=0
    ADAPTER: enabled=1 value=3
    BATTERY_SOC: enabled=0 value=0
    BATTERY_TEMP: enabled=0 value=0

6.2 日志分析

关键日志标签: power_vote

典型日志输出:

bash
# 创建投票对象
[power_vote] vote object FCC_VOTABLE create ok

# 投票操作
[power_vote] FCC_VOTABLE: USB_TYPE,2 vote on of value=500 eff_result=500,500 eff_id=2

# 结果变化
[power_vote] FCC_VOTABLE: effective vote is now 500 voted by USB_TYPE,2

# 相同投票去重
[power_vote] FCC_VOTABLE: USB_TYPE,2 same vote on of value=500
[power_vote] FCC_VOTABLE: USB_TYPE,2 ignore same vote on of value=500

6.3 实时监控脚本

bash
#!/bin/bash
# 监控投票变化

echo "=== Power Vote Monitor ==="
dmesg -w | grep "power_vote" | grep "effective vote" | while read line; do
    timestamp=$(date '+%H:%M:%S')
    echo "[$timestamp] $line"
done

7. 设计模式与最佳实践

7.1 策略模式应用

Power Vote 是策略模式的典型应用:

角色映射:

  • Context(上下文)power_vote_object
  • Strategy(策略接口)power_vote_set_min/max/any
  • ConcreteStrategy(具体策略):三种仲裁算法

优势:

  • 仲裁算法可灵活切换(创建时指定type)
  • 新增策略无需修改现有代码
  • 策略独立封装便于测试

7.2 使用建议

1. 选择合适的仲裁类型

c
// 限制类参数 → SET_MIN
power_vote_create_object("max_current", POWER_VOTE_SET_MIN, ...);
power_vote_create_object("max_voltage", POWER_VOTE_SET_MIN, ...);

// 优先级类参数 → SET_MAX
power_vote_create_object("charge_priority", POWER_VOTE_SET_MAX, ...);
power_vote_create_object("power_mode", POWER_VOTE_SET_MAX, ...);

// 开关类参数 → SET_ANY
power_vote_create_object("input_suspend", POWER_VOTE_SET_ANY, ...);
power_vote_create_object("otg_enable", POWER_VOTE_SET_ANY, ...);

2. 客户端命名规范

c
// 好的命名(清晰表达投票来源)
power_vote_set("FCC", "THERMAL_HIGH_TEMP", true, 1000);
power_vote_set("FCC", "USB_SDP_LIMIT", true, 500);
power_vote_set("FCC", "BATTERY_AGED", true, 1500);

// 不好的命名(难以理解)
power_vote_set("FCC", "client1", true, 1000);
power_vote_set("FCC", "mgr", true, 500);

3. 回调函数设计

c
// 好的设计:简洁清晰
static int fcc_callback(struct power_vote_object *obj, 
                        void *data, int result, const char *client)
{
    hwlog_info("Set FCC: %d mA (by %s)\n", result, client);
    return charger_set_fcc(result);
}

// 不好的设计:逻辑过于复杂
static int bad_callback(struct power_vote_object *obj, 
                        void *data, int result, const char *client)
{
    // 回调函数内不应包含复杂业务逻辑
    if (result > 2000) {
        check_battery_health();
        update_ui_status();
        notify_thermal_manager();
    }
    ...
}

4. 线程安全

c
// 模块内部已加锁(外部无需额外加锁)
power_vote_set("FCC", "THERMAL", true, 1000);  // 线程安全

// 查询时可选择是否加锁
value = power_vote_get_effective_result_locked("FCC", true);  // 加锁查询

7.3 常见陷阱

陷阱1:忘记禁用投票

c
// 错误:条件不满足时未禁用
if (temp > 45) {
    power_vote_set("FCC", "THERMAL", true, 1000);
}
// 温度降低后,投票仍然生效!

// 正确:显式禁用
if (temp > 45) {
    power_vote_set("FCC", "THERMAL", true, 1000);
} else {
    power_vote_set("FCC", "THERMAL", false, 0);
}

陷阱2:SET_ANY 误用 value

c
// 错误:SET_ANY 类型忽略 value 值
power_vote_set("USB_SUSPEND", "OTG", true, 1);   // value=1 无意义
power_vote_set("USB_SUSPEND", "TEMP", true, 0);  // value=0 无意义

// 正确:value 统一设置为 0
power_vote_set("USB_SUSPEND", "OTG", true, 0);
power_vote_set("USB_SUSPEND", "TEMP", false, 0);

陷阱3:回调函数阻塞

c
// 错误:回调函数内长时间阻塞
static int bad_callback(struct power_vote_object *obj, 
                        void *data, int result, const char *client)
{
    msleep(1000);  // ❌ 阻塞 1 秒,影响其他投票
    return 0;
}

// 正确:异步处理
static int good_callback(struct power_vote_object *obj, 
                         void *data, int result, const char *client)
{
    schedule_work(&update_work);  // ✓ 异步执行
    return 0;
}

8. 技术要点总结

8.1 核心优势

优势说明对比传统方案
解耦合各模块独立投票,互不影响传统方案需硬编码优先级
可追溯清晰记录最终结果由谁决定难以调试多模块冲突
灵活性运行时动态调整投票修改逻辑需重新编译
线程安全内置互斥锁保护全局变量易竞争
可调试debugfs 实时查看所有投票传统方案无可视化

这个Vote机制的核心思想是分布式决策、集中仲裁:

  • 各个子系统根据自己的需求独立投票
  • Vote机制自动根据规则(MIN/MAX/ANY)计算最终结果
  • 只有当结果改变时才触发回调,避免重复操作
  • 通过取最小值(MIN)确保最严格的限制总是生效,保证安全性

这种设计在复杂的充电管理系统中非常实用,能够优雅地处理多个因素(温度、用户设置、硬件能力、协议限制等)对充电参数的影响。

8.2 性能特性

  • 时间复杂度:O(N),N 为客户端数量(最大32)
  • 空间复杂度:每个投票对象约 2KB
  • 锁粒度:对象级别(不同对象可并发操作)
  • 优化:相同投票去重,避免无效回调

8.3 应用统计

在 MATE X5 电源系统中的典型应用:

投票对象类型分布:
├─ SET_MIN(60%):充电电流、输入电压、温度限制等
├─ SET_MAX(25%):充电模式、功率等级、优先级等
└─ SET_ANY(15%):输入暂停、OTG 使能、充电使能等

客户端数量分布:
├─ 1-5 个客户端(70%):简单场景
├─ 6-10 个客户端(20%):复杂场景
└─ 10+ 个客户端(10%):极端场景