第一部分 电源管理全景:Suspend/Resume 流程

1.1 Suspend/Resume 核心概念

Suspend (系统挂起) 和 Resume (系统唤醒) 是电源管理中最重要的两个操作。Suspend 将系统进入低功耗状态,保留内存内容但暂停 CPU 和外设。Resume 将系统恢复到正常工作状态。Android 系统通过 Linux 内核的 PM (Power Management) 框架实现 Suspend/Resume,并支持多种唤醒源(如电源键、RTC、USB 等)。

1.1.1 Suspend/Resume 状态迁移图

[正常工作状态 (Working State)]
    ↓
[用户触发 Suspend]
    ↓
[PM 核心层 (kernel/power/main.c)]
    ├── 通知设备准备挂起 (suspend_prepare)
    ├── 冻结进程 (freeze_processes)
    ├── 同步文件系统 (sync_filesystems)
    ├── 设备电源管理 (device_power_suspend)
    ├── 进入低功耗状态 (suspend_enter)
    └── 等待唤醒事件
    ↓
[唤醒事件触发]
    ↓
[PM 核心层 (kernel/power/main.c)]
    ├── 设备电源恢复 (device_power_resume)
    ├── 解冻进程 (thaw_processes)
    ├── 通知设备恢复完成 (suspend_complete)
    └── 恢复到正常工作状态

1.1.2 Suspend/Resume 架构

[PM 核心层 (kernel/power/main.c)]
    ├── suspend_prepare() → 准备挂起
    ├── suspend_enter() → 进入低功耗状态
    ├── suspend_finish() → 完成挂起
    └── suspend_complete() → 完成恢复
    ↓
[设备 PM 层 (drivers/base/power/main.c)]
    ├── dpm_prepare() → 设备准备
    ├── dpm_suspend() → 设备挂起
    ├── dpm_resume() → 设备恢复
    └── dpm_complete() → 设备完成
    ↓
[平台 PM 层 (arch/arm64/kernel/suspend.c)]
    ├── platform_suspend_prepare() → 平台准备
    ├── platform_suspend_enter() → 平台进入
    ├── platform_suspend_finish() → 平台完成
    └── platform_wake_up() → 平台唤醒
    ↓
[硬件 PM 层]
    ├── CPU 空闲状态 (cpuidle)
    ├── GIC 唤醒中断
    └── 电源域 (PM Domain)

1.2 核心数据结构

1.2.1 PM 核心结构 (代码出处: kernel/power/main.c)

// 代码出处: kernel/power/main.c
​
/**
 * @struct pm_state
 * @brief PM 状态结构,表示系统电源状态。
 */
struct pm_state {
    const char *label;              /**< 状态标签 */
    const char *name;               /**< 状态名称 */
    suspend_state_t state;          /**< 挂起状态值 */
    int (*enter)(suspend_state_t state); /**< 进入状态函数 */
    int (*valid)(suspend_state_t state); /**< 检查状态是否有效 */
    int (*prepare)(suspend_state_t state); /**< 准备函数 */
    int (*finish)(suspend_state_t state); /**< 完成函数 */
    int (*wake)(suspend_state_t state); /**< 唤醒函数 */
};
​
/**
 * @struct suspend_data
 * @brief 挂起数据结构,存储挂起过程中的状态。
 */
struct suspend_data {
    suspend_state_t state;          /**< 挂起状态 */
    struct pm_message msg;          /**< PM 消息 */
    int error;                      /**< 错误码 */
    unsigned long start_time;       /**< 开始时间 */
    unsigned long end_time;         /**< 结束时间 */
    struct list_head device_list;   /**< 设备列表 */
    struct list_head platform_list; /**< 平台列表 */
    spinlock_t lock;                /**< 自旋锁 */
};
​
/**
 * @struct pm_message
 * @brief PM 消息结构,用于传递电源管理事件。
 */
struct pm_message {
    int event;                      /**< 事件类型 */
    int data;                       /**< 事件数据 */
    union {
        struct {
            int flag;               /**< 标志位 */
        } flags;
        struct {
            int suspend_id;         /**< 挂起 ID */
        } suspend;
    } u;
};
​
/**
 * @struct device_pm_state
 * @brief 设备 PM 状态结构。
 */
struct device_pm_state {
    struct device *dev;             /**< 设备指针 */
    int state;                      /**< 设备状态 (D0/D1/D2/D3) */
    unsigned long flags;            /**< 标志位 */
    struct list_head list;          /**< 链表节点 */
    struct device_pm_ops *ops;      /**< 设备 PM 操作 */
    spinlock_t lock;                /**< 自旋锁 */
    struct completion completion;   /**< 完成信号 */
    bool is_suspended;              /**< 是否已挂起 */
    bool can_wakeup;                /**< 是否支持唤醒 */
    int wakeup_irq;                 /**< 唤醒中断号 */
    void *private_data;             /**< 私有数据 */
};

1.3 核心代码实现

1.3.1 核心 Suspend 流程 (代码出处: kernel/power/main.c)

// 代码出处: kernel/power/main.c
​
/**
 * @brief 核心挂起函数。
 * @param state 挂起状态
 * @return 0 成功,负数错误
 */
int suspend_enter(suspend_state_t state)
{
    struct suspend_data data;
    int ret;
​
    // 1. 初始化挂起数据
    data.state = state;
    data.msg.event = PM_EVENT_SUSPEND;
    data.error = 0;
    data.start_time = jiffies;
    INIT_LIST_HEAD(&data.device_list);
    INIT_LIST_HEAD(&data.platform_list);
    spin_lock_init(&data.lock);
​
    // 2. 检查是否支持该状态
    if (!pm_suspend_valid(state)) {
        return -EINVAL;
    }
​
    // 3. 准备挂起
    ret = suspend_prepare(state);
    if (ret < 0) {
        goto error;
    }
​
    // 4. 冻结进程
    ret = freeze_processes();
    if (ret < 0) {
        goto error_prepare;
    }
​
    // 5. 执行设备挂起
    ret = dpm_suspend(PMSG_SUSPEND);
    if (ret < 0) {
        goto error_freeze;
    }
​
    // 6. 同步文件系统
    sys_sync();
​
    // 7. 进入低功耗状态
    ret = suspend_enter_low_power(state);
    if (ret < 0) {
        goto error_dpm;
    }
​
    // 8. 执行设备恢复
    ret = dpm_resume(PMSG_RESUME);
    if (ret < 0) {
        goto error_dpm;
    }
​
    // 9. 解冻进程
    thaw_processes();
​
    // 10. 完成挂起
    suspend_finish(state);
​
    data.end_time = jiffies;
    pm_print_times(&data);
​
    return 0;
​
error_dpm:
    dpm_resume(PMSG_RESUME);
error_freeze:
    thaw_processes();
error_prepare:
    suspend_finish(state);
error:
    return ret;
}
​
/**
 * @brief 挂起准备函数。
 * @param state 挂起状态
 * @return 0 成功,负数错误
 */
int suspend_prepare(suspend_state_t state)
{
    int ret;
​
    // 1. 冻结内核线程
    ret = freeze_kernel_threads();
    if (ret < 0) {
        return ret;
    }
​
    // 2. 检查唤醒源
    ret = pm_wakeup_prepare(state);
    if (ret < 0) {
        goto error;
    }
​
    // 3. 准备平台
    ret = platform_suspend_prepare(state);
    if (ret < 0) {
        goto error;
    }
​
    return 0;
​
error:
    thaw_kernel_threads();
    return ret;
}
​
/**
 * @brief 进入低功耗状态。
 * @param state 挂起状态
 * @return 0 成功,负数错误
 */
int suspend_enter_low_power(suspend_state_t state)
{
    struct cpuidle_state *idle_state;
    int ret;
​
    // 1. 选择空闲状态
    idle_state = cpuidle_select();
    if (!idle_state) {
        return -EINVAL;
    }
​
    // 2. 进入低功耗状态
    ret = cpuidle_enter(idle_state);
    if (ret < 0) {
        return ret;
    }
​
    // 3. 等待唤醒事件
    ret = wait_for_wakeup_event();
    if (ret < 0) {
        return ret;
    }
​
    return 0;
}

1.3.2 设备 PM 管理 (代码出处: drivers/base/power/main.c)

// 代码出处: drivers/base/power/main.c
​
/**
 * @brief 设备挂起。
 * @param msg PM 消息
 * @return 0 成功,负数错误
 */
int dpm_suspend(pm_message_t msg)
{
    struct device *dev;
    int ret = 0;
​
    // 1. 遍历所有设备
    list_for_each_entry(dev, &device_list, power.list) {
        if (dev->power.no_suspend) {
            continue;
        }
​
        // 2. 检查设备是否支持唤醒
        if (dev->power.can_wakeup) {
            dev->power.wakeup = true;
        }
​
        // 3. 执行设备挂起
        ret = device_suspend(dev, msg);
        if (ret < 0) {
            dev_err(dev, "Device suspend failed: %d\n", ret);
            break;
        }
    }
​
    return ret;
}
​
/**
 * @brief 设备恢复。
 * @param msg PM 消息
 * @return 0 成功,负数错误
 */
int dpm_resume(pm_message_t msg)
{
    struct device *dev;
    int ret = 0;
​
    // 1. 遍历所有设备 (反向顺序)
    list_for_each_entry_reverse(dev, &device_list, power.list) {
        if (dev->power.no_suspend) {
            continue;
        }
​
        // 2. 执行设备恢复
        ret = device_resume(dev, msg);
        if (ret < 0) {
            dev_err(dev, "Device resume failed: %d\n", ret);
            break;
        }
    }
​
    return ret;
}
​
/**
 * @brief 设备 PM 操作注册。
 * @param dev 设备指针
 * @param ops 设备 PM 操作
 * @return 0 成功,负数错误
 */
int device_pm_ops_register(struct device *dev, struct device_pm_ops *ops)
{
    if (!dev || !ops) {
        return -EINVAL;
    }
​
    dev->power.ops = ops;
    dev->power.can_wakeup = ops->wakeup ? true : false;
    dev->power.no_suspend = ops->no_suspend ? true : false;
​
    return 0;
}

1.3.3 平台 PM 层 (代码出处: arch/arm64/kernel/suspend.c)

// 代码出处: arch/arm64/kernel/suspend.c
​
/**
 * @brief 平台挂起准备。
 * @param state 挂起状态
 * @return 0 成功,负数错误
 */
int platform_suspend_prepare(suspend_state_t state)
{
    int ret;
​
    // 1. 保存 CPU 状态
    ret = cpu_suspend_prepare();
    if (ret < 0) {
        return ret;
    }
​
    // 2. 保存 GIC 状态
    ret = gic_suspend_prepare();
    if (ret < 0) {
        goto error_gic;
    }
​
    // 3. 保存电源域状态
    ret = pm_domain_suspend_prepare();
    if (ret < 0) {
        goto error_pd;
    }
​
    return 0;
​
error_pd:
    gic_suspend_finish();
error_gic:
    cpu_suspend_finish();
    return ret;
}
​
/**
 * @brief 平台挂起进入。
 * @param state 挂起状态
 * @return 0 成功,负数错误
 */
int platform_suspend_enter(suspend_state_t state)
{
    // 1. 执行 ARM64 特定挂起
    cpu_suspend_enter(state);
​
    // 2. 进入 WFI (Wait For Interrupt)
    wfi();
​
    return 0;
}
​
/**
 * @brief 平台唤醒。
 * @param state 挂起状态
 * @return 0 成功,负数错误
 */
int platform_wake_up(suspend_state_t state)
{
    int ret;
​
    // 1. 唤醒 CPU
    ret = cpu_wake_up();
    if (ret < 0) {
        return ret;
    }
​
    // 2. 唤醒 GIC
    ret = gic_wake_up();
    if (ret < 0) {
        return ret;
    }
​
    // 3. 唤醒电源域
    ret = pm_domain_wake_up();
    if (ret < 0) {
        return ret;
    }
​
    return 0;
}

1.3.4 唤醒源管理 (代码出处: drivers/base/power/wakeup.c)

// 代码出处: drivers/base/power/wakeup.c
​
/**
 * @struct wakeup_source
 * @brief 唤醒源结构。
 */
struct wakeup_source {
    const char *name;               /**< 唤醒源名称 */
    struct list_head list;          /**< 链表节点 */
    struct device *dev;             /**< 关联的设备 */
    int irq;                        /**< 中断号 */
    bool active;                    /**< 是否活跃 */
    unsigned long wakeup_count;     /**< 唤醒次数 */
    unsigned long last_wakeup_time; /**< 上次唤醒时间 */
    unsigned long total_wakeup_time; /**< 总唤醒时间 */
    spinlock_t lock;                /**< 自旋锁 */
};
​
/**
 * @brief 注册唤醒源。
 * @param name 唤醒源名称
 * @param irq 中断号
 * @return 0 成功,负数错误
 */
int wakeup_source_register(const char *name, int irq)
{
    struct wakeup_source *ws;
    int ret;
​
    // 1. 分配唤醒源结构
    ws = kzalloc(sizeof(*ws), GFP_KERNEL);
    if (!ws) {
        return -ENOMEM;
    }
​
    ws->name = name;
    ws->irq = irq;
    ws->active = false;
    ws->wakeup_count = 0;
    ws->last_wakeup_time = 0;
    ws->total_wakeup_time = 0;
    spin_lock_init(&ws->lock);
​
    // 2. 添加到全局列表
    list_add_tail(&ws->list, &wakeup_source_list);
​
    // 3. 申请中断
    ret = request_irq(irq, wakeup_irq_handler, IRQF_TRIGGER_RISING,
                      name, ws);
    if (ret < 0) {
        list_del(&ws->list);
        kfree(ws);
        return ret;
    }
​
    return 0;
}
​
/**
 * @brief 唤醒中断处理函数。
 * @param irq 中断号
 * @param dev_id 设备私有数据
 * @return IRQ_HANDLED
 */
static irqreturn_t wakeup_irq_handler(int irq, void *dev_id)
{
    struct wakeup_source *ws = dev_id;
​
    // 1. 更新唤醒统计
    spin_lock(&ws->lock);
    ws->wakeup_count++;
    ws->last_wakeup_time = jiffies;
    ws->active = true;
    spin_unlock(&ws->lock);
​
    // 2. 调度唤醒工作队列
    schedule_work(&wakeup_work);
​
    return IRQ_HANDLED;
}
​
/**
 * @brief 唤醒工作队列处理。
 */
static void wakeup_work_handler(struct work_struct *work)
{
    // 1. 触发系统唤醒
    pm_wakeup_event();
​
    // 2. 重置唤醒源
    // ...
}

1.4 软件设计模式树形分析

Suspend/Resume 设计模式
├── 策略模式 (Strategy Pattern)
│   ├── 挂起策略:根据状态选择不同的挂起方式
│   └── 唤醒策略:根据唤醒源选择不同的唤醒方式
├── 观察者模式 (Observer Pattern)
│   ├── wakeup_irq_handler():观察唤醒中断事件
│   └── device_pm_ops_register():观察设备 PM 状态
├── 适配器模式 (Adapter Pattern)
│   ├── dpm_suspend():适配设备挂起操作
│   └── dpm_resume():适配设备恢复操作
├── 状态模式 (State Pattern)
│   └── 系统状态 (WORKING/SUSPENDING/SUSPENDED/RESUMING)
└── 模板方法模式 (Template Method Pattern)
    └── suspend_enter():定义了 Suspend 的标准流程 (准备->冻结->挂起->恢复->解冻)

1.5 Suspend/Resume 调试核心难点

1.5.1 挂起失败

现象:Suspend 过程中卡住,系统无法进入低功耗状态。

原因

  1. 设备挂起函数返回错误。

  2. 进程冻结超时。

  3. 唤醒源冲突。

调试方法

  1. 使用 echo "power" > /sys/power/pm_trace 跟踪挂起。

  2. 使用 dmesg | grep "suspend" 查看挂起日志。

  3. 使用 cat /proc/pid/status | grep "State" 检查进程状态。

1.5.2 唤醒失败

现象:系统挂起后无法唤醒,按电源键无响应。

原因

  1. 唤醒中断未正确配置。

  2. GIC 中断未使能。

  3. 电源域未正确上电。

调试方法

  1. 检查 /proc/interrupts 查看唤醒中断统计。

  2. 使用 cat /sys/kernel/debug/wakeup_sources 查看唤醒源。

  3. 检查 GIC 和电源域配置。

1.5.3 挂起后设备无法恢复

现象:系统唤醒后,某些设备无法正常工作。

原因

  1. 设备恢复函数未正确执行。

  2. 设备状态未保存。

  3. 电源域未完全恢复。

调试方法

  1. 检查 dpm_resume 返回值。

  2. 检查设备驱动的 resume 函数。

  3. 检查电源域恢复状态。

1.6 与其他模块的协同

模块 协同方式 调试关键点
进程管理 冻结和解冻进程 进程状态、优先级
设备驱动 实现设备挂起/恢复 状态保存、电源管理
平台 PM 提供平台级挂起/恢复 CPU 状态、GIC 状态
中断控制器 处理唤醒中断 中断配置、唤醒源
电源域 管理设备电源 上下电序列、依赖关系
Cpuidle 管理 CPU 空闲状态 空闲状态选择、进入/退出

第二部分 电源管理全景:DVFS 与 温控

2.1 DVFS 与 温控 核心概念

DVFS (Dynamic Voltage and Frequency Scaling) 是嵌入式系统中最重要的电源管理技术之一,它根据系统负载动态调整 CPU/GPU 的工作电压和频率,在性能与功耗之间取得平衡。温控 (Thermal Management) 则是确保系统在安全温度范围内工作,防止过热损坏硬件。

2.1.1 DVFS 架构

[DVFS 系统]
    ├── [CPUFreq 核心层] (drivers/cpufreq/cpufreq.c)
    │   ├── 频率表管理 (freq_table)
    │   ├── 策略管理 (governor)
    │   ├── 通知链 (notifier chain)
    │   └── sysfs 接口
    ├── [CPUFreq 驱动] (drivers/cpufreq/rockchip-cpufreq.c)
    │   ├── 频率调整 (set_freq)
    │   ├── 电压调整 (set_voltage)
    │   └── 硬件配置 (clk/regulator)
    ├── [DevFreq 核心] (drivers/devfreq/devfreq.c)
    │   ├── 设备频率管理 (device freq)
    │   ├── 策略管理 (governor)
    │   └── sysfs 接口
    ├── [DevFreq 驱动] (drivers/devfreq/rockchip-dfreq.c)
    │   ├── GPU 频率/电压调整
    │   ├── DDR 频率/电压调整
    │   └── 硬件配置 (clk/regulator)
    └── [温控子系统] (drivers/thermal/thermal_core.c)
        ├── 温度传感器驱动 (tsadc)
        ├── 冷却设备 (cooling device)
        ├── 温控策略 (governor)
        └── 热区管理 (thermal zone)

2.1.2 DVFS 与 温控 工作流程

[系统负载变化]
    ↓
[CPUFreq governor 触发]
    ↓
[计算目标频率]
    ↓
[CPUFreq 驱动调整频率]
    ↓
[频率调整完成]
    ↓
[温度变化]
    ↓
[温度传感器触发中断]
    ↓
[Thermal governor 触发]
    ↓
[计算冷却需求]
    ↓
[调用冷却设备降频]
    ↓
[温度稳定]

2.2 核心数据结构

2.2.1 CPUFreq 核心结构 (代码出处: drivers/cpufreq/cpufreq.c)

// 代码出处: drivers/cpufreq/cpufreq.c
​
/**
 * @struct cpufreq_policy
 * @brief CPUFreq 策略结构,管理一个 CPU 的 DVFS 策略。
 */
struct cpufreq_policy {
    unsigned int cpu;               /**< CPU 编号 */
    unsigned int min;               /**< 最小频率 */
    unsigned int max;               /**< 最大频率 */
    unsigned int cur;               /**< 当前频率 */
    unsigned int target;            /**< 目标频率 */
    unsigned int freq_table_size;   /**< 频率表大小 */
    struct cpufreq_frequency_table *freq_table; /**< 频率表 */
    struct cpufreq_governor *governor; /**< 治理器 */
    struct cpufreq_driver *driver;  /**< 驱动 */
    unsigned int policy;            /**< 策略 (POLICY_MAX/POLICY_MIN) */
    unsigned int flags;             /**< 标志位 */
    struct device *dev;             /**< 设备指针 */
    struct device_node *np;         /**< 设备树节点 */
    spinlock_t lock;                /**< 自旋锁 */
    struct work_struct update_work; /**< 更新工作队列 */
    struct list_head list;          /**< 链表节点 */
};
​
/**
 * @struct cpufreq_frequency_table
 * @brief CPUFreq 频率表结构。
 */
struct cpufreq_frequency_table {
    unsigned int frequency;         /**< 频率 (kHz) */
    unsigned int voltage;           /**< 电压 (µV) */
    unsigned int flag;              /**< 标志位 */
    unsigned int index;             /**< 索引 */
};
​
/**
 * @struct cpufreq_governor
 * @brief CPUFreq 治理器结构。
 */
struct cpufreq_governor {
    char name[20];                  /**< 治理器名称 (ondemand/interactive) */
    int (*governor)(struct cpufreq_policy *policy, unsigned int *target);
    int (*init)(struct cpufreq_policy *policy);
    int (*exit)(struct cpufreq_policy *policy);
    int (*start)(struct cpufreq_policy *policy);
    int (*stop)(struct cpufreq_policy *policy);
    struct list_head list;          /**< 链表节点 */
    void *private_data;             /**< 私有数据 */
};

2.2.2 DevFreq 结构 (代码出处: drivers/devfreq/devfreq.c)

// 代码出处: drivers/devfreq/devfreq.c
​
/**
 * @struct devfreq
 * @brief DevFreq 设备结构,管理一个设备的频率。
 */
struct devfreq {
    struct device *dev;             /**< 设备指针 */
    struct devfreq_dev_profile *profile; /**< 设备配置 */
    struct devfreq_governor *governor; /**< 治理器 */
    unsigned long min_freq;         /**< 最小频率 */
    unsigned long max_freq;         /**< 最大频率 */
    unsigned long cur_freq;         /**< 当前频率 */
    unsigned long target_freq;      /**< 目标频率 */
    struct devfreq_frequency_table *freq_table; /**< 频率表 */
    struct devfreq_ops *ops;        /**< 操作 */
    spinlock_t lock;                /**< 自旋锁 */
    struct work_struct update_work; /**< 更新工作队列 */
    struct list_head list;          /**< 链表节点 */
};
​
/**
 * @struct devfreq_dev_profile
 * @brief DevFreq 设备配置结构。
 */
struct devfreq_dev_profile {
    unsigned long initial_freq;     /**< 初始频率 */
    unsigned long min_freq;         /**< 最小频率 */
    unsigned long max_freq;         /**< 最大频率 */
    unsigned long polling_ms;       /**< 轮询间隔 */
    int (*target)(struct devfreq *devfreq, unsigned long *freq);
    int (*get_dev_status)(struct devfreq *devfreq, struct devfreq_dev_status *status);
    int (*get_cur_freq)(struct devfreq *devfreq, unsigned long *freq);
    int (*set_cur_freq)(struct devfreq *devfreq, unsigned long freq);
    int (*get_event)(struct devfreq *devfreq, int event);
    int (*set_event)(struct devfreq *devfreq, int event);
};

2.2.3 温控结构 (代码出处: drivers/thermal/thermal_core.c)

// 代码出处: drivers/thermal/thermal_core.c
​
/**
 * @struct thermal_zone_device
 * @brief 热区设备结构,管理一个温度区域。
 */
struct thermal_zone_device {
    char name[20];                  /**< 热区名称 */
    int id;                         /**< 热区 ID */
    struct device *dev;             /**< 设备指针 */
    struct thermal_zone_ops *ops;   /**< 热区操作 */
    int trips;                      /**< 温度触发点数量 */
    struct thermal_trip *trips;     /**< 温度触发点列表 */
    struct thermal_governor *governor; /**< 治理器 */
    int temperature;                /**< 当前温度 */
    int target_temp;                /**< 目标温度 */
    int polling_delay;              /**< 轮询延迟 */
    struct list_head cooling_devices; /**< 冷却设备列表 */
    spinlock_t lock;                /**< 自旋锁 */
    struct work_struct work;        /**< 工作队列 */
    int state;                      /**< 热区状态 */
};
​
/**
 * @struct cooling_device
 * @brief 冷却设备结构,用于降温。
 */
struct cooling_device {
    char name[20];                  /**< 冷却设备名称 */
    int id;                         /**< 冷却设备 ID */
    struct device *dev;             /**< 设备指针 */
    int max_state;                  /**< 最大状态 (最高降频等级) */
    int cur_state;                  /**< 当前状态 */
    int min_state;                  /**< 最小状态 */
    struct cooling_device_ops *ops; /**< 冷却设备操作 */
    struct list_head list;          /**< 链表节点 */
    void *private_data;             /**< 私有数据 */
};

2.3 核心代码实现

2.3.1 CPUFreq 核心逻辑 (代码出处: drivers/cpufreq/cpufreq.c)

// 代码出处: drivers/cpufreq/cpufreq.c
​
/**
 * @brief CPUFreq 频率调整。
 * @param policy 策略指针
 * @param target_freq 目标频率
 * @return 0 成功,负数错误
 */
int cpufreq_target(struct cpufreq_policy *policy, unsigned int target_freq)
{
    struct cpufreq_frequency_table *freq_table;
    unsigned int freq = target_freq;
    int ret;
​
    if (!policy || !policy->freq_table) {
        return -EINVAL;
    }
​
    // 1. 检查频率范围
    if (freq < policy->min) {
        freq = policy->min;
    } else if (freq > policy->max) {
        freq = policy->max;
    }
​
    // 2. 查找最近的可用频率
    freq_table = policy->freq_table;
    for (int i = 0; i < policy->freq_table_size; i++) {
        if (freq_table[i].frequency == freq) {
            break;
        }
        // 选择最接近的频率
        if (freq_table[i].frequency < freq) {
            // 向下取整
            if (i > 0 && freq_table[i-1].frequency > freq) {
                freq = freq_table[i-1].frequency;
            }
        }
    }
​
    // 3. 检查是否需要调整
    if (freq == policy->cur) {
        return 0;
    }
​
    // 4. 调用驱动调整频率
    ret = policy->driver->target(policy, freq);
    if (ret < 0) {
        return ret;
    }
​
    // 5. 更新当前频率
    policy->cur = freq;
​
    // 6. 通知策略更新
    cpufreq_notify_transition(policy, freq);
​
    return 0;
}
​
/**
 * @brief CPUFreq 治理器 (ondemand)。
 * @param policy 策略指针
 * @param target 目标频率
 * @return 0 成功,负数错误
 */
int cpufreq_governor_ondemand(struct cpufreq_policy *policy, unsigned int *target)
{
    unsigned long load;
    unsigned int freq;
    int ret;
​
    // 1. 计算当前 CPU 负载
    load = cpufreq_get_load(policy);
    if (load < 0) {
        return load;
    }
​
    // 2. 计算目标频率
    freq = policy->cur;
    if (load > 80) {
        // 高负载,升频
        freq = policy->max;
    } else if (load < 20) {
        // 低负载,降频
        freq = policy->min;
    } else {
        // 中等负载,按比例调整
        freq = policy->min + (policy->max - policy->min) * load / 100;
    }
​
    *target = freq;
​
    return 0;
}

2.3.2 DevFreq 核心逻辑 (代码出处: drivers/devfreq/devfreq.c)

// 代码出处: drivers/devfreq/devfreq.c
​
/**
 * @brief DevFreq 频率调整。
 * @param devfreq DevFreq 设备指针
 * @param target_freq 目标频率
 * @return 0 成功,负数错误
 */
int devfreq_target(struct devfreq *devfreq, unsigned long target_freq)
{
    unsigned long old_freq;
    int ret;
​
    if (!devfreq) {
        return -EINVAL;
    }
​
    // 1. 检查频率范围
    if (target_freq < devfreq->min_freq) {
        target_freq = devfreq->min_freq;
    } else if (target_freq > devfreq->max_freq) {
        target_freq = devfreq->max_freq;
    }
​
    // 2. 获取当前频率
    old_freq = devfreq->cur_freq;
​
    // 3. 检查是否需要调整
    if (target_freq == old_freq) {
        return 0;
    }
​
    // 4. 调用驱动调整频率
    ret = devfreq->ops->target(devfreq, &target_freq);
    if (ret < 0) {
        return ret;
    }
​
    // 5. 更新当前频率
    devfreq->cur_freq = target_freq;
​
    // 6. 通知策略更新
    devfreq_notify_transition(devfreq, target_freq, old_freq);
​
    return 0;
}
​
/**
 * @brief DevFreq 治理器 (simple_ondemand)。
 * @param devfreq DevFreq 设备指针
 * @param target 目标频率
 * @return 0 成功,负数错误
 */
int devfreq_governor_simple_ondemand(struct devfreq *devfreq, unsigned long *target)
{
    unsigned long load;
    unsigned long freq;
​
    // 1. 获取负载
    load = devfreq_get_load(devfreq);
    if (load < 0) {
        return load;
    }
​
    // 2. 计算目标频率
    freq = devfreq->cur_freq;
    if (load > 80) {
        freq = devfreq->max_freq;
    } else if (load < 20) {
        freq = devfreq->min_freq;
    } else {
        freq = devfreq->min_freq + (devfreq->max_freq - devfreq->min_freq) * load / 100;
    }
​
    *target = freq;
​
    return 0;
}

2.3.3 温控核心逻辑 (代码出处: drivers/thermal/thermal_core.c)

// 代码出处: drivers/thermal/thermal_core.c
​
/**
 * @brief 温度检测与冷却处理。
 * @param tz 热区设备指针
 * @return 0 成功,负数错误
 */
int thermal_zone_update(struct thermal_zone_device *tz)
{
    int temp;
    int ret;
​
    // 1. 读取当前温度
    ret = tz->ops->get_temp(tz, &temp);
    if (ret < 0) {
        return ret;
    }
​
    // 2. 更新温度
    tz->temperature = temp;
​
    // 3. 检查温度阈值
    for (int i = 0; i < tz->trips; i++) {
        struct thermal_trip *trip = &tz->trips[i];
        if (temp >= trip->temperature) {
            // 触发冷却
            ret = thermal_zone_trigger_cooling(tz, trip);
            if (ret < 0) {
                return ret;
            }
        }
    }
​
    return 0;
}
​
/**
 * @brief 触发冷却。
 * @param tz 热区设备指针
 * @param trip 触发点
 * @return 0 成功,负数错误
 */
int thermal_zone_trigger_cooling(struct thermal_zone_device *tz,
                                  struct thermal_trip *trip)
{
    struct cooling_device *cdev;
    int state;
    int ret = 0;
​
    // 1. 计算冷却状态
    state = (tz->temperature - trip->temperature) / 10;
    if (state < 0) {
        state = 0;
    }
    if (state > tz->cooling_devices[0].max_state) {
        state = tz->cooling_devices[0].max_state;
    }
​
    // 2. 遍历冷却设备
    list_for_each_entry(cdev, &tz->cooling_devices, list) {
        // 3. 设置冷却设备状态
        ret = cdev->ops->set_state(cdev, state);
        if (ret < 0) {
            return ret;
        }
    }
​
    return 0;
}

2.3.4 温度传感器驱动 (代码出处: drivers/thermal/rockchip_thermal.c)

// 代码出处: drivers/thermal/rockchip_thermal.c
​
/**
 * @brief 读取温度传感器。
 * @param tz 热区设备指针
 * @param temp 温度输出
 * @return 0 成功,负数错误
 */
static int rockchip_thermal_get_temp(struct thermal_zone_device *tz, int *temp)
{
    struct rockchip_thermal_data *data = thermal_zone_get_drvdata(tz);
    u32 val;
    int temperature;
​
    // 1. 读取传感器寄存器
    val = readl(data->base + TSADC_DATA_REG);
    val &= 0xFFF;
​
    // 2. 转换为摄氏温度 (芯片特定公式)
    temperature = (val * 500) - 40000;
​
    *temp = temperature;
​
    return 0;
}
​
/**
 * @brief 初始化温度传感器。
 * @param pdev Platform 设备指针
 * @param data 私有数据
 * @return 0 成功,负数错误
 */
int rockchip_thermal_init(struct platform_device *pdev, struct rockchip_thermal_data *data)
{
    struct device *dev = &pdev->dev;
​
    // 1. 获取时钟
    data->pclk = devm_clk_get(dev, "pclk");
    if (IS_ERR(data->pclk)) {
        return PTR_ERR(data->pclk);
    }
    clk_prepare_enable(data->pclk);
​
    // 2. 获取中断
    data->irq = platform_get_irq(pdev, 0);
    if (data->irq < 0) {
        return data->irq;
    }
​
    // 3. 初始化硬件
    writel(0x1, data->base + TSADC_CON);
    writel(0x1, data->base + TSADC_INT_EN);
​
    // 4. 注册热区
    data->tzd = thermal_zone_device_register("rockchip-thermal", 0, 0,
                                              data, &rockchip_thermal_ops,
                                              NULL, 0, 0);
    if (IS_ERR(data->tzd)) {
        return PTR_ERR(data->tzd);
    }
​
    return 0;
}

2.3.5 冷却设备实现 (代码出处: drivers/thermal/cpu_cooling.c)

// 代码出处: drivers/thermal/cpu_cooling.c
​
/**
 * @brief CPU 冷却设备创建。
 * @param cpufreq_policy CPUFreq 策略指针
 * @return 冷却设备指针
 */
struct cooling_device *cpu_cooling_device_create(struct cpufreq_policy *policy)
{
    struct cooling_device *cdev;
​
    // 1. 分配冷却设备
    cdev = kzalloc(sizeof(*cdev), GFP_KERNEL);
    if (!cdev) {
        return NULL;
    }
​
    cdev->name = "cpu-cooling";
    cdev->id = policy->cpu;
    cdev->max_state = policy->freq_table_size - 1;
    cdev->cur_state = 0;
    cdev->min_state = 0;
    cdev->ops = &cpu_cooling_ops;
    cdev->private_data = policy;
​
    // 2. 注册冷却设备
    thermal_cooling_device_register(cdev);
​
    return cdev;
}
​
/**
 * @brief 设置 CPU 冷却设备状态。
 * @param cdev 冷却设备指针
 * @param state 状态值
 * @return 0 成功,负数错误
 */
int cpu_cooling_set_state(struct cooling_device *cdev, int state)
{
    struct cpufreq_policy *policy = cdev->private_data;
    unsigned int freq;
​
    // 1. 检查状态范围
    if (state < cdev->min_state) {
        state = cdev->min_state;
    }
    if (state > cdev->max_state) {
        state = cdev->max_state;
    }
​
    // 2. 计算目标频率
    if (state == cdev->max_state) {
        freq = policy->min;
    } else {
        freq = policy->freq_table[state].frequency;
    }
​
    // 3. 设置 CPU 频率
    cpufreq_target(policy, freq);
​
    cdev->cur_state = state;
​
    return 0;
}

2.3.6 DVFS 与 温控 协同 (代码出处: drivers/thermal/thermal_core.c)

// 代码出处: drivers/thermal/thermal_core.c
​
/**
 * @brief 温控策略: step_wise。
 * @param tz 热区设备指针
 * @param trip 触发点
 * @return 0 成功,负数错误
 */
int thermal_governor_step_wise(struct thermal_zone_device *tz,
                                struct thermal_trip *trip)
{
    struct cooling_device *cdev;
    int state;
    int ret;
​
    // 1. 计算当前状态
    if (tz->temperature < trip->temperature) {
        // 温度已恢复,逐步降低冷却等级
        state = tz->cooling_devices[0].cur_state - 1;
        if (state < 0) {
            state = 0;
        }
    } else if (tz->temperature > trip->temperature + 10) {
        // 温度继续升高,提高冷却等级
        state = tz->cooling_devices[0].cur_state + 1;
        if (state > tz->cooling_devices[0].max_state) {
            state = tz->cooling_devices[0].max_state;
        }
    } else {
        // 温度稳定,保持当前等级
        state = tz->cooling_devices[0].cur_state;
    }
​
    // 2. 应用冷却
    list_for_each_entry(cdev, &tz->cooling_devices, list) {
        ret = cdev->ops->set_state(cdev, state);
        if (ret < 0) {
            return ret;
        }
    }
​
    return 0;
}
​
/**
 * @brief 智能温控策略。
 * @param tz 热区设备指针
 * @param trip 触发点
 * @return 0 成功,负数错误
 */
int thermal_governor_intelligent(struct thermal_zone_device *tz,
                                  struct thermal_trip *trip)
{
    struct cooling_device *cdev;
    int state;
    int ret;
​
    // 1. 基于负载计算目标状态
    unsigned long load = cpufreq_get_load(tz->cooling_devices[0].private_data);
    int target_state = (load * tz->cooling_devices[0].max_state) / 100;
​
    // 2. 调整冷却状态
    if (tz->temperature > trip->temperature) {
        state = target_state + 1;
        if (state > tz->cooling_devices[0].max_state) {
            state = tz->cooling_devices[0].max_state;
        }
    } else if (tz->temperature < trip->temperature - 10) {
        state = target_state - 1;
        if (state < 0) {
            state = 0;
        }
    } else {
        state = target_state;
    }
​
    // 3. 应用冷却
    list_for_each_entry(cdev, &tz->cooling_devices, list) {
        ret = cdev->ops->set_state(cdev, state);
        if (ret < 0) {
            return ret;
        }
    }
​
    return 0;
}

2.4 软件设计模式树形分析

DVFS 与 温控 设计模式
├── 策略模式 (Strategy Pattern)
│   ├── cpufreq_governor_ondemand:ondemand 降频策略
│   ├── devfreq_governor_simple_ondemand:简单降频策略
│   ├── thermal_governor_step_wise:步进冷却策略
│   └── thermal_governor_intelligent:智能冷却策略
├── 观察者模式 (Observer Pattern)
│   ├── cpufreq_notify_transition():观察频率变化
│   └── thermal_zone_update():观察温度变化
├── 适配器模式 (Adapter Pattern)
│   ├── cpu_cooling_device_create():适配 CPUFreq 到冷却设备
│   └── devfreq_get_load():适配设备负载
├── 工厂模式 (Factory Pattern)
│   ├── cpufreq_register_driver():注册 CPUFreq 驱动
│   └── thermal_cooling_device_register():注册冷却设备
└── 模板方法模式 (Template Method Pattern)
    ├── cpufreq_target():定义了频率调整的标准流程
    └── thermal_zone_update():定义了温度检测的标准流程

2.5 DVFS 与 温控 调试核心难点

2.5.1 频率切换延迟

现象:频率切换时系统响应慢,帧率不稳定。

原因

  1. 频率切换时锁被持有。

  2. 电压调整时间长。

  3. 策略切换频繁。

调试方法

  1. 使用 perf stat -e cpu_freq:* 监控频率切换。

  2. 检查 cpufreq_target 执行时间。

  3. 调整策略阈值。

2.5.2 温度读取错误

现象:温度读数与实际温度偏差大,导致错误触发冷却。

原因

  1. 传感器校准不准确。

  2. 采样频率过高或过低。

  3. 中断处理延迟。

调试方法

  1. 使用 cat /sys/class/thermal/thermal_zone*/temp 查看温度。

  2. 检查传感器转换公式。

  3. 调整采样频率。

2.5.3 冷却设备不响应

现象:温度超标后 CPU 频率未降低,系统过热。

原因

  1. 冷却设备未注册。

  2. 冷却设备状态设置失败。

  3. 策略配置错误。

调试方法

  1. 检查 /sys/class/thermal/cooling_device* 设备是否存在。

  2. 手动设置冷却状态测试。

  3. 调整策略配置。

2.6 与其他模块的协同

模块 协同方式 调试关键点
CPUFreq 提供 CPU 频率调整 频率表、策略选择
DevFreq 提供 GPU/DDR 频率调整 频率表、策略选择
温控 提供温度检测和冷却 传感器、冷却设备
时钟控制器 提供频率调整时钟 时钟频率、分频器
电压调节器 提供电压调整 电压范围、稳定性
设备树 配置 DVFS 参数 频率表、电压值

第三部分 Android 安全机制:SELinux

3.1 SELinux 核心概念

SELinux (Security-Enhanced Linux) 是 Linux 内核的安全模块,通过 强制访问控制 (MAC, Mandatory Access Control) 机制,对进程、文件、设备等系统资源进行细粒度的权限管理。Android 从 4.3 版本开始引入 SELinux,并在后续版本中逐步收紧安全策略,成为 Android 安全体系的基石。

3.1.1 SELinux 与 DAC 的对比

特性 DAC (传统权限) SELinux (MAC)
权限控制 基于用户和组 基于安全上下文
控制粒度 粗粒度 (读/写/执行) 细粒度 (具体操作)
权限继承 子进程继承父进程权限 子进程有自己的上下文
恶意程序防护 弱 (可继承所有权限) 强 (即使 root 也受限制)
策略配置 简单 (chmod) 复杂 (策略文件)
生效范围 全局 可针对特定进程/文件

3.1.2 SELinux 核心架构

[用户空间策略]
    ├── 策略文件 (policy.conf)
    ├── 策略包 (policy.31)
    └── 策略加载工具 (load_policy)
    ↓
[SELinux 内核模块]
    ├── 访问控制服务器 (avc)
    ├── 策略引擎 (ss)
    ├── 上下文管理 (context)
    └── 审计日志 (audit)
    ↓
[系统调用]
    ├── 进程访问
    ├── 文件访问
    └── 设备访问
    ↓
[LSM 钩子]
    ├── inode_* hooks
    ├── file_* hooks
    ├── task_* hooks
    └── socket_* hooks

3.1.3 SELinux 工作流程

[访问请求] (进程请求访问文件/设备)
    ↓
[SELinux 检查] (avc_has_perm)
    ↓
[查找 AVC 缓存] → [命中] → [返回允许/拒绝]
    ↓ [未命中]
[查找策略] (security_compute_av)
    ↓
[计算权限] (selinux_has_perm)
    ↓
[记录审计日志] (avc_audit)
    ↓
[返回结果]

3.2 核心数据结构

3.2.1 SELinux 核心结构 (代码出处: security/selinux/avc.c)

// 代码出处: security/selinux/avc.c
​
/**
 * @struct avc_entry
 * @brief AVC (Access Vector Cache) 条目结构。
 */
struct avc_entry {
    struct avc_node *node;          /**< 关联节点 */
    u32 ssid;                       /**< 源安全上下文 ID */
    u32 tsid;                       /**< 目标安全上下文 ID */
    u16 tclass;                     /**< 对象类 */
    struct av_decision avd;         /**< 访问决策 */
    u16 seqno;                      /**< 序列号 */
};
​
/**
 * @struct avc_node
 * @brief AVC 节点结构。
 */
struct avc_node {
    struct avc_entry ae;            /**< 关联条目 */
    struct rb_node rb;              /**< 红黑树节点 */
    struct list_head list;          /**< 链表节点 */
    atomic_t count;                 /**< 引用计数 */
    u32 key;                        /**< 哈希键 */
};
​
/**
 * @struct avc_cache
 * @brief AVC 缓存结构。
 */
struct avc_cache {
    struct rb_root root;            /**< 红黑树根 */
    struct list_head lru;           /**< LRU 链表 */
    u32 entries;                    /**< 条目数 */
    u32 max_entries;                /**< 最大条目数 */
    spinlock_t lock;                /**< 自旋锁 */
};
​
/**
 * @struct selinux_state
 * @brief SELinux 状态结构。
 */
struct selinux_state {
    bool initialized;               /**< 是否已初始化 */
    bool enforcing;                 /**< 是否强制执行 */
    struct avc_cache avc;           /**< AVC 缓存 */
    struct policydb *policy;        /**< 策略数据库 */
    struct sidtab *sidtab;          /**< 安全上下文 ID 表 */
    struct list_head policy_list;   /**< 策略列表 */
    struct work_struct reload_work; /**< 重载工作队列 */
    spinlock_t lock;                /**< 自旋锁 */
    struct audit_controller audit;  /**< 审计控制器 */
};

3.3 核心代码实现

3.3.1 SELinux 初始化 (代码出处: security/selinux/selinux.c)

// 代码出处: security/selinux/selinux.c
​
/**
 * @brief SELinux 核心初始化。
 * @return 0 成功,负数错误
 */
static int __init selinux_init(void)
{
    int ret;
​
    // 1. 注册 LSM
    ret = register_security(&selinux_ops);
    if (ret < 0) {
        pr_err("SELinux: Failed to register LSM\n");
        return ret;
    }
​
    // 2. 初始化 AVC 缓存
    ret = avc_init();
    if (ret < 0) {
        pr_err("SELinux: Failed to init AVC\n");
        return ret;
    }
​
    // 3. 初始化策略数据库
    ret = policydb_init(&selinux_state.policy);
    if (ret < 0) {
        pr_err("SELinux: Failed to init policy\n");
        return ret;
    }
​
    // 4. 初始化审计
    ret = audit_init();
    if (ret < 0) {
        pr_err("SELinux: Failed to init audit\n");
        return ret;
    }
​
    // 5. 注册 sysfs 接口
    ret = securityfs_create_file("selinux", 0444, NULL, NULL, &selinux_fops);
    if (ret < 0) {
        pr_err("SELinux: Failed to create securityfs\n");
        return ret;
    }
​
    pr_info("SELinux: Initialized\n");
    return 0;
}
​
/**
 * @brief 加载 SELinux 策略。
 * @param policy_data 策略数据
 * @param policy_len 策略长度
 * @return 0 成功,负数错误
 */
int selinux_load_policy(const char *policy_data, size_t policy_len)
{
    struct policydb *policydb = selinux_state.policy;
    int ret;
​
    // 1. 检查策略数据
    if (!policy_data || policy_len == 0) {
        return -EINVAL;
    }
​
    // 2. 解析策略
    ret = policydb_read(policydb, policy_data, policy_len);
    if (ret < 0) {
        pr_err("SELinux: Failed to read policy\n");
        return ret;
    }
​
    // 3. 构建 SID 表
    ret = sidtab_init(&selinux_state.sidtab);
    if (ret < 0) {
        pr_err("SELinux: Failed to init sidtab\n");
        return ret;
    }
​
    // 4. 设置强制执行模式
    selinux_state.enforcing = true;
​
    // 5. 触发策略更新
    selinux_state.policy_updated = true;
​
    return 0;
}

3.3.2 访问控制检查 (代码出处: security/selinux/avc.c)

// 代码出处: security/selinux/avc.c
​
/**
 * @brief AVC 访问检查。
 * @param ssid 源安全上下文 ID
 * @param tsid 目标安全上下文 ID
 * @param tclass 对象类
 * @param requested 请求的权限
 * @param avd 访问决策输出
 * @return 0 允许,负数拒绝
 */
int avc_has_perm(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd)
{
    struct avc_node *node;
    int ret;
​
    // 1. 检查缓存
    node = avc_lookup(ssid, tsid, tclass);
    if (node) {
        *avd = node->ae.avd;
        if (avd->allowed & requested) {
            return 0;
        } else {
            return -EACCES;
        }
    }
​
    // 2. 未命中缓存,查询策略
    ret = security_compute_av(ssid, tsid, tclass, requested, avd);
    if (ret < 0) {
        return ret;
    }
​
    // 3. 插入缓存
    avc_insert(ssid, tsid, tclass, avd);
​
    // 4. 检查权限
    if (avd->allowed & requested) {
        return 0;
    } else {
        return -EACCES;
    }
}
​
/**
 * @brief 策略计算权限。
 * @param ssid 源安全上下文 ID
 * @param tsid 目标安全上下文 ID
 * @param tclass 对象类
 * @param requested 请求的权限
 * @param avd 访问决策输出
 * @return 0 成功,负数错误
 */
int security_compute_av(u32 ssid, u32 tsid, u16 tclass, u32 requested, struct av_decision *avd)
{
    struct context *scontext = sidtab_search(ssid);
    struct context *tcontext = sidtab_search(tsid);
    struct policydb *policydb = selinux_state.policy;
    struct avtab_key key;
    struct avtab_node *node;
    u32 perm_mask;
​
    // 1. 检查上下文
    if (!scontext || !tcontext) {
        return -EINVAL;
    }
​
    // 2. 查找策略
    key.source_type = scontext->type;
    key.target_type = tcontext->type;
    key.target_class = tclass;
    key.perm_mask = requested;
​
    node = avtab_search(&policydb->avtab, &key);
    if (!node) {
        return -EACCES;
    }
​
    // 3. 计算权限
    avd->allowed = node->datum->allowed & requested;
    avd->auditallow = node->datum->auditallow & requested;
    avd->auditdeny = node->datum->auditdeny & requested;
​
    return 0;
}

3.3.3 安全上下文管理 (代码出处: security/selinux/ss/context.c)

// 代码出处: security/selinux/ss/context.c
​
/**
 * @struct context
 * @brief 安全上下文结构。
 */
struct context {
    u32 type;                       /**< 类型 */
    u32 role;                       /**< 角色 */
    u32 user;                       /**< 用户 */
    char *str;                      /**< 字符串表示 */
    struct {
        u32 count;                  /**< 长度 */
        u32 *values;                /**< 值列表 */
    } mls;                          /**< 多级安全 */
    u32 flags;                      /**< 标志 */
};
​
/**
 * @brief 解析安全上下文。
 * @param str 字符串表示
 * @param ctx 上下文输出
 * @return 0 成功,负数错误
 */
int context_from_string(const char *str, struct context *ctx)
{
    char *scontext = kstrdup(str, GFP_KERNEL);
    char *tmp = scontext;
    char *token;
    int ret = 0;
​
    if (!scontext) {
        return -ENOMEM;
    }
​
    // 1. 解析用户
    token = strsep(&tmp, ":");
    if (!token) {
        ret = -EINVAL;
        goto out;
    }
    ctx->user = user_by_name(token);
    if (!ctx->user) {
        ret = -EINVAL;
        goto out;
    }
​
    // 2. 解析角色
    token = strsep(&tmp, ":");
    if (!token) {
        ret = -EINVAL;
        goto out;
    }
    ctx->role = role_by_name(token);
    if (!ctx->role) {
        ret = -EINVAL;
        goto out;
    }
​
    // 3. 解析类型
    token = strsep(&tmp, ":");
    if (!token) {
        ret = -EINVAL;
        goto out;
    }
    ctx->type = type_by_name(token);
    if (!ctx->type) {
        ret = -EINVAL;
        goto out;
    }
​
    // 4. 解析 MLS (如果存在)
    if (tmp && *tmp) {
        ctx->mls.values = kcalloc(1, sizeof(u32), GFP_KERNEL);
        if (!ctx->mls.values) {
            ret = -ENOMEM;
            goto out;
        }
        ctx->mls.count = 1;
        ctx->mls.values[0] = mls_level_by_name(tmp);
        if (!ctx->mls.values[0]) {
            ret = -EINVAL;
            goto out;
        }
    }
​
out:
    kfree(scontext);
    return ret;
}

3.3.4 策略加载与验证 (代码出处: security/selinux/ss/policydb.c)

// 代码出处: security/selinux/ss/policydb.c
​
/**
 * @struct policydb
 * @brief 策略数据库结构。
 */
struct policydb {
    struct avtab avtab;             /**< 权限表 */
    struct hashtab *types;          /**< 类型表 */
    struct hashtab *roles;          /**< 角色表 */
    struct hashtab *users;          /**< 用户表 */
    struct hashtab *classes;        /**< 类表 */
    struct hashtab *perms;          /**< 权限表 */
    struct hashtab *mls_ops;        /**< MLS 操作 */
    u32 version;                    /**< 策略版本 */
    int (*read)(struct policydb *p, void *data, size_t len);
    int (*write)(struct policydb *p, void *data, size_t len);
    void (*destroy)(struct policydb *p);
};
​
/**
 * @brief 读取策略文件。
 * @param p 策略数据库
 * @param data 策略数据
 * @param len 策略长度
 * @return 0 成功,负数错误
 */
int policydb_read(struct policydb *p, const char *data, size_t len)
{
    struct avtab_key key;
    struct avtab_node *node;
    int ret;
​
    // 1. 检查版本
    u32 version = *(u32 *)data;
    if (version < POLICYDB_VERSION_MIN || version > POLICYDB_VERSION_MAX) {
        return -EINVAL;
    }
​
    // 2. 初始化权限表
    ret = avtab_init(&p->avtab);
    if (ret < 0) {
        return ret;
    }
​
    // 3. 读取权限表
    ret = avtab_read(&p->avtab, data + 4, len - 4);
    if (ret < 0) {
        goto out;
    }
​
    // 4. 读取类型表
    ret = hashtab_read(&p->types, data + 4 + p->avtab.size, len - 4 - p->avtab.size);
    if (ret < 0) {
        goto out;
    }
​
    return 0;
​
out:
    avtab_destroy(&p->avtab);
    return ret;
}

3.3.5 Android 特有 SELinux 策略 (代码出处: system/sepolicy/)

// 代码出处: system/sepolicy/te_macros
​
// 1. 定义 Android 特有权限
type foo_service, domain;
type foo_service_exec, exec_type, file_type, vendor_file_type;
​
init_daemon_domain(foo_service);
​
// 2. 授予权限
allow foo_service self:capability net_admin;
allow foo_service self:udp_socket { create bind connect };
allow foo_service self:tcp_socket { create bind connect };
allow foo_service sysfs:file rw_file_perms;
allow foo_service proc_net:file rw_file_perms;
​
// 3. 定义 Android 特定宏
# 宏定义: 为服务添加权限
define(`init_daemon_domain', `
    type $1, domain;
    type $1_exec, exec_type, file_type;
    init_daemon_domain($1, $1_exec)
')
​
# 宏定义: 允许访问网络
define(`allow_network', `
    allow $1 self:udp_socket { create bind connect };
    allow $1 self:tcp_socket { create bind connect };
    allow $1 net_iface:udp_socket { read write };
')

3.4 软件设计模式树形分析

SELinux 设计模式
├── 策略模式 (Strategy Pattern)
│   ├── avc_has_perm():访问检查策略
│   └── security_compute_av():权限计算策略
├── 观察者模式 (Observer Pattern)
│   ├── avc_lookup():观察 AVC 缓存
│   └── selinux_load_policy():观察策略更新
├── 适配器模式 (Adapter Pattern)
│   ├── context_from_string():适配字符串到上下文
│   └── policydb_read():适配二进制策略文件
├── 工厂模式 (Factory Pattern)
│   ├── selinux_init():创建 SELinux 状态
│   └── avc_init():创建 AVC 缓存
└── 模板方法模式 (Template Method Pattern)
    └── avc_has_perm():定义了访问检查的标准流程 (缓存查找->策略计算->审计)

3.5 SELinux 调试核心难点

3.5.1 权限拒绝

现象avc: denied { read } for pid=1234 comm="app" 日志。

原因

  1. 进程没有访问目标文件的权限。

  2. 文件上下文配置错误。

  3. 策略加载失败。

调试方法

  1. 使用 audit2allow -i /var/log/audit.log 生成允许规则。

  2. 检查文件上下文:ls -Z /path/to/file

  3. 临时禁用 SELinux:setenforce 0

3.5.2 策略加载失败

现象load_policy 返回 -EINVAL

原因

  1. 策略文件损坏。

  2. 策略版本不匹配。

  3. 策略编译错误。

调试方法

  1. 使用 checkpolicy -c policy.conf 验证策略文件。

  2. 使用 sepolicy-inspect policy.31 查看策略内容。

  3. 检查策略编译日志。

3.5.3 上下文配置错误

现象:进程或文件的上下文不是预期的。

原因

  1. file_contexts 配置错误。

  2. mac_permissions.xml 配置错误。

  3. 进程未正确设置上下文。

调试方法

  1. 检查 /sys/fs/selinux/context

  2. 查看 file_contexts 文件。

  3. 检查 mac_permissions.xml 配置。

3.6 与其他模块的协同

模块 协同方式 调试关键点
LSM 框架 提供安全钩子 钩子注册、调用顺序
审计系统 记录安全事件 审计日志、事件过滤
进程管理 进程上下文管理 上下文继承、创建
文件系统 文件上下文管理 上下文存储、xattr
用户空间 通过 libselinux 访问 策略编译、上下文转换
设备驱动 设备上下文管理 设备节点、权限

第四部分 Android 安全机制:TrustZone

4.1 TrustZone 核心概念

TrustZone 是 ARM 架构提供的硬件安全扩展技术,它通过硬件隔离将处理器划分为 安全世界 (Secure World)非安全世界 (Normal World)。安全世界运行可信执行环境 (TEE, Trusted Execution Environment),用于处理敏感数据和安全操作;非安全世界运行普通操作系统 (如 Android/Linux)。TrustZone 是 Android 安全体系的核心基础,广泛应用于指纹识别、支付、密钥管理等场景。

4.1.1 ARM64 异常级别与 TrustZone

[非安全世界 (Normal World)]                    [安全世界 (Secure World)]
    ↓                                                ↓
[EL0 (应用层)]                                 [EL0 (TEE 应用)]
    ↓                                                ↓
[EL1 (内核层)]                                 [EL1 (TEE 内核/OP-TEE)]
    ↓                                                ↓
[EL2 (Hypervisor)]                            [EL2 (Secure Hypervisor)]
    ↓                                                ↓
[EL3 (Monitor)] → [SMC (Secure Monitor Call)] ← [EL3 (Monitor)]

4.1.2 TrustZone 架构

[非安全世界]
    ├── Android/Linux (EL1)
    │   ├── 应用层 (EL0)
    │   ├── 内核层 (EL1)
    │   └── TEE 客户端 API (libteec)
    ↓
[EL3 Monitor (Monitor Mode)]
    ├── SMC 处理 (SMC handler)
    ├── 上下文切换 (context switch)
    └── 安全中断处理 (secure interrupt)
    ↓
[安全世界]
    ├── OP-TEE (EL1)
    │   ├── TEE 内核 (OP-TEE Core)
    │   ├── TEE 应用 (Trusted Application)
    │   └── TEE 客户端 API (libteec)
    └── TEE 驱动 (Linux 内核)
        └── drivers/tee/optee/

4.1.3 TEE 工作流程

[非安全世界应用]
    ↓
1. 调用 TEE 客户端 API (libteec)
    ↓
2. 通过 TEE 驱动 (optee) 发送请求
    ↓
3. 触发 SMC (Secure Monitor Call)
    ↓
4. EL3 Monitor 切换到安全世界
    ↓
5. OP-TEE 内核接收请求
    ↓
6. 调用 Trusted Application (TA)
    ↓
7. TA 处理安全操作
    ↓
8. 返回结果给 OP-TEE 内核
    ↓
9. 触发 SMC 返回非安全世界
    ↓
10. TEE 驱动返回结果给应用

4.2 核心数据结构

4.2.1 TEE 驱动核心结构 (代码出处: drivers/tee/optee/optee_core.c)

// 代码出处: drivers/tee/optee/optee_core.c
​
/**
 * @struct optee
 * @brief OP-TEE 核心结构,管理 TEE 设备。
 */
struct optee {
    struct tee_device *teedev;          /**< TEE 设备 */
    struct tee_shm_pool *pool;          /**< 共享内存池 */
    void *secure_monitor;               /**< 安全监视器 */
    struct optee_ops *ops;              /**< 操作函数 */
    struct device *dev;                 /**< 设备指针 */
    struct list_head teedev_list;       /**< TEE 设备列表 */
    spinlock_t lock;                    /**< 自旋锁 */
    struct work_struct cmd_work;        /**< 命令工作队列 */
    struct work_struct msg_work;        /**< 消息工作队列 */
};
​
/**
 * @struct optee_session
 * @brief TEE 会话结构,代表一个 TEE 会话。
 */
struct optee_session {
    struct list_head list;              /**< 会话列表节点 */
    u32 session_id;                     /**< 会话 ID */
    u32 client_id;                      /**< 客户端 ID */
    struct tee_context *ctx;            /**< TEE 上下文 */
    void *private_data;                 /**< 私有数据 */
};
​
/**
 * @struct optee_cmd
 * @brief TEE 命令结构。
 */
struct optee_cmd {
    u32 cmd;                            /**< 命令类型 */
    u32 flags;                          /**< 命令标志 */
    u32 ref_count;                      /**< 引用计数 */
    struct tee_shm *shm;                /**< 共享内存 */
    struct optee_session *session;      /**< 会话 */
    struct optee_buf *params;           /**< 参数列表 */
    u32 num_params;                     /**< 参数数量 */
    struct completion *done;            /**< 完成信号 */
    int ret;                            /**< 返回结果 */
};

4.2.2 共享内存管理 (代码出处: drivers/tee/tee_shm.c)

// 代码出处: drivers/tee/tee_shm.c
​
/**
 * @struct tee_shm
 * @brief TEE 共享内存结构。
 */
struct tee_shm {
    struct kref ref;                    /**< 引用计数 */
    struct tee_device *teedev;          /**< 所属设备 */
    struct tee_shm_pool *pool;          /**< 所属内存池 */
    void *kaddr;                        /**< 内核地址 */
    dma_addr_t dma_addr;                /**< DMA 地址 */
    u32 flags;                          /**< 标志 */
    size_t size;                        /**< 大小 */
    struct page **pages;                /**< 页面数组 */
    struct list_head list;              /**< 链表节点 */
    spinlock_t lock;                    /**< 自旋锁 */
};

4.3 核心代码实现

4.3.1 OP-TEE 驱动初始化 (代码出处: drivers/tee/optee/optee_core.c)

// 代码出处: drivers/tee/optee/optee_core.c
​
/**
 * @brief OP-TEE 驱动初始化。
 * @param pdev Platform 设备指针
 * @return 0 成功,负数错误
 */
static int optee_probe(struct platform_device *pdev)
{
    struct optee *optee;
    struct tee_device *teedev;
    struct tee_shm_pool *pool;
    int ret;
​
    // 1. 分配 OP-TEE 结构
    optee = devm_kzalloc(&pdev->dev, sizeof(*optee), GFP_KERNEL);
    if (!optee) {
        return -ENOMEM;
    }
​
    // 2. 初始化共享内存池
    pool = tee_shm_pool_alloc(&pdev->dev, &optee_pool_ops);
    if (IS_ERR(pool)) {
        return PTR_ERR(pool);
    }
    optee->pool = pool;
​
    // 3. 创建 TEE 设备
    teedev = tee_device_alloc(tee_cdev, NULL, pool, &pdev->dev,
                               &optee_tee_ops, "optee");
    if (IS_ERR(teedev)) {
        ret = PTR_ERR(teedev);
        goto error_pool;
    }
​
    optee->teedev = teedev;
    optee->dev = &pdev->dev;
    spin_lock_init(&optee->lock);
    INIT_LIST_HEAD(&optee->teedev_list);
​
    // 4. 注册 TEE 设备
    ret = tee_device_register(teedev);
    if (ret < 0) {
        goto error_device;
    }
​
    // 5. 创建 SMC 接口
    ret = tee_get_smc_abi(&optee->secure_monitor);
    if (ret < 0) {
        goto error_device;
    }
​
    // 6. 设置平台数据
    platform_set_drvdata(pdev, optee);
​
    pr_info("OP-TEE driver initialized\n");
    return 0;
​
error_device:
    tee_device_unregister(teedev);
error_pool:
    tee_shm_pool_free(pool);
    return ret;
}

4.3.2 SMC 调用处理 (代码出处: drivers/tee/optee/optee_smc.c)

// 代码出处: drivers/tee/optee/optee_smc.c
​
/**
 * @brief 执行 SMC 调用。
 * @param smc_fn 函数 ID
 * @param arg0 参数 0
 * @param arg1 参数 1
 * @param arg2 参数 2
 * @param arg3 参数 3
 * @return SMC 结果
 */
u64 optee_smc_call(u64 smc_fn, u64 arg0, u64 arg1, u64 arg2, u64 arg3)
{
    struct arm_smccc_res res;
    u64 result;
​
    // 1. 准备 SMC 参数
    struct arm_smccc_args args = {
        .a0 = smc_fn,
        .a1 = arg0,
        .a2 = arg1,
        .a3 = arg2,
        .a4 = arg3,
        .a5 = 0,
        .a6 = 0,
        .a7 = 0,
    };
​
    // 2. 执行 SMC 调用
    arm_smccc_smc(&args, &res);
​
    // 3. 检查结果
    if (res.a0 != SMC_OK) {
        pr_err("SMC call failed: %lld\n", res.a0);
        return -EIO;
    }
​
    result = res.a1;
    return result;
}
​
/**
 * @brief 处理 TEE 命令。
 * @param optee OP-TEE 指针
 * @param cmd 命令指针
 * @return 0 成功,负数错误
 */
int optee_handle_cmd(struct optee *optee, struct optee_cmd *cmd)
{
    u64 result;
    int ret;
​
    // 1. 检查命令类型
    switch (cmd->cmd) {
    case TEE_CMD_OPEN_SESSION:
        result = optee_smc_call(SMC_CMD_OPEN_SESSION,
                                cmd->session->client_id,
                                cmd->session->session_id,
                                0, 0);
        break;
    case TEE_CMD_INVOKE_COMMAND:
        result = optee_smc_call(SMC_CMD_INVOKE_COMMAND,
                                cmd->session->client_id,
                                cmd->session->session_id,
                                cmd->shm->dma_addr,
                                cmd->params[0].value);
        break;
    case TEE_CMD_CLOSE_SESSION:
        result = optee_smc_call(SMC_CMD_CLOSE_SESSION,
                                cmd->session->client_id,
                                cmd->session->session_id,
                                0, 0);
        break;
    default:
        return -EINVAL;
    }
​
    // 2. 检查结果
    if (result == SMC_ERROR) {
        return -EIO;
    }
​
    // 3. 完成命令
    if (cmd->done) {
        complete(cmd->done);
    }
​
    return 0;
}

4.3.3 共享内存管理 (代码出处: drivers/tee/tee_shm.c)

// 代码出处: drivers/tee/tee_shm.c
​
/**
 * @brief 创建共享内存。
 * @param teedev TEE 设备指针
 * @param size 大小
 * @param flags 标志
 * @return 共享内存指针,失败返回 ERR_PTR
 */
struct tee_shm *tee_shm_alloc(struct tee_device *teedev, size_t size, u32 flags)
{
    struct tee_shm *shm;
    int ret;
​
    // 1. 分配共享内存结构
    shm = kzalloc(sizeof(*shm), GFP_KERNEL);
    if (!shm) {
        return ERR_PTR(-ENOMEM);
    }
​
    shm->teedev = teedev;
    shm->size = size;
    shm->flags = flags;
    kref_init(&shm->ref);
    spin_lock_init(&shm->lock);
    INIT_LIST_HEAD(&shm->list);
​
    // 2. 分配物理页面
    shm->pages = kcalloc(size >> PAGE_SHIFT, sizeof(struct page *), GFP_KERNEL);
    if (!shm->pages) {
        kfree(shm);
        return ERR_PTR(-ENOMEM);
    }
​
    for (int i = 0; i < (size >> PAGE_SHIFT); i++) {
        shm->pages[i] = alloc_page(GFP_KERNEL);
        if (!shm->pages[i]) {
            ret = -ENOMEM;
            goto error;
        }
    }
​
    // 3. 获取 DMA 地址
    shm->dma_addr = dma_map_page(teedev->dev, shm->pages[0], 0, size, DMA_BIDIRECTIONAL);
    if (dma_mapping_error(teedev->dev, shm->dma_addr)) {
        ret = -ENOMEM;
        goto error;
    }
​
    // 4. 获取内核地址
    shm->kaddr = page_address(shm->pages[0]);
​
    return shm;
​
error:
    for (int i = 0; i < (size >> PAGE_SHIFT); i++) {
        if (shm->pages[i]) {
            __free_page(shm->pages[i]);
        }
    }
    kfree(shm->pages);
    kfree(shm);
    return ERR_PTR(ret);
}
​
/**
 * @brief 释放共享内存。
 * @param shm 共享内存指针
 */
void tee_shm_free(struct tee_shm *shm)
{
    if (!shm) {
        return;
    }
​
    // 1. 取消 DMA 映射
    dma_unmap_page(shm->teedev->dev, shm->dma_addr, shm->size, DMA_BIDIRECTIONAL);
​
    // 2. 释放物理页面
    for (int i = 0; i < (shm->size >> PAGE_SHIFT); i++) {
        if (shm->pages[i]) {
            __free_page(shm->pages[i]);
        }
    }
    kfree(shm->pages);
​
    // 3. 释放结构
    kfree(shm);
}

4.3.4 TEE 会话管理 (代码出处: drivers/tee/tee_core.c)

// 代码出处: drivers/tee/tee_core.c
​
/**
 * @brief 创建 TEE 会话。
 * @param ctx TEE 上下文
 * @param ta_uuid 可信应用 UUID
 * @return 会话 ID,负数错误
 */
int tee_session_create(struct tee_context *ctx, const u8 *ta_uuid)
{
    struct optee_session *session;
    struct optee *optee = ctx->teedev->priv;
    int ret;
​
    // 1. 分配会话结构
    session = kzalloc(sizeof(*session), GFP_KERNEL);
    if (!session) {
        return -ENOMEM;
    }
​
    session->ctx = ctx;
    session->client_id = ctx->client_id;
    session->session_id = ++ctx->session_counter;
    INIT_LIST_HEAD(&session->list);
​
    // 2. 打开 TEE 会话
    ret = optee_handle_cmd(optee, &(struct optee_cmd){
        .cmd = TEE_CMD_OPEN_SESSION,
        .session = session,
    });
​
    if (ret < 0) {
        kfree(session);
        return ret;
    }
​
    // 3. 添加到会话列表
    spin_lock(&optee->lock);
    list_add_tail(&session->list, &optee->teedev_list);
    spin_unlock(&optee->lock);
​
    return session->session_id;
}
​
/**
 * @brief 关闭 TEE 会话。
 * @param ctx TEE 上下文
 * @param session_id 会话 ID
 * @return 0 成功,负数错误
 */
int tee_session_close(struct tee_context *ctx, u32 session_id)
{
    struct optee *optee = ctx->teedev->priv;
    struct optee_session *session;
    int ret = -ENOENT;
​
    // 1. 查找会话
    spin_lock(&optee->lock);
    list_for_each_entry(session, &optee->teedev_list, list) {
        if (session->session_id == session_id) {
            list_del(&session->list);
            spin_unlock(&optee->lock);
            // 2. 关闭会话
            ret = optee_handle_cmd(optee, &(struct optee_cmd){
                .cmd = TEE_CMD_CLOSE_SESSION,
                .session = session,
            });
            kfree(session);
            return ret;
        }
    }
    spin_unlock(&optee->lock);
​
    return ret;
}

4.3.5 可信应用调用 (代码出处: drivers/tee/tee_core.c)

// 代码出处: drivers/tee/tee_core.c
​
/**
 * @brief 调用可信应用。
 * @param ctx TEE 上下文
 * @param session_id 会话 ID
 * @param cmd_id 命令 ID
 * @param params 参数列表
 * @param num_params 参数数量
 * @return 0 成功,负数错误
 */
int tee_invoke_command(struct tee_context *ctx, u32 session_id,
                       u32 cmd_id, struct tee_param *params, u32 num_params)
{
    struct optee *optee = ctx->teedev->priv;
    struct optee_session *session;
    struct optee_cmd cmd;
    int ret = -ENOENT;
​
    // 1. 查找会话
    spin_lock(&optee->lock);
    list_for_each_entry(session, &optee->teedev_list, list) {
        if (session->session_id == session_id) {
            spin_unlock(&optee->lock);
            // 2. 构建命令
            cmd.cmd = TEE_CMD_INVOKE_COMMAND;
            cmd.session = session;
            cmd.params = params;
            cmd.num_params = num_params;
            cmd.shm = params[0].shm;
            cmd.done = &ctx->completion;
​
            // 3. 执行命令
            ret = optee_handle_cmd(optee, &cmd);
            if (ret < 0) {
                return ret;
            }
​
            // 4. 等待完成
            if (cmd.done) {
                wait_for_completion(cmd.done);
            }
​
            return ret;
        }
    }
    spin_unlock(&optee->lock);
​
    return ret;
}

4.3.6 用户空间接口 (代码出处: drivers/tee/tee_core.c)

// 代码出处: drivers/tee/tee_core.c
​
/**
 * @brief TEE 设备文件操作。
 */
static const struct file_operations tee_fops = {
    .owner = THIS_MODULE,
    .open = tee_open,
    .release = tee_release,
    .unlocked_ioctl = tee_ioctl,
    .compat_ioctl = tee_ioctl,
    .mmap = tee_mmap,
};
​
/**
 * @brief TEE ioctl 处理。
 * @param file 文件指针
 * @param cmd ioctl 命令
 * @param arg 参数
 * @return 0 成功,负数错误
 */
static long tee_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    struct tee_context *ctx = file->private_data;
    struct optee *optee = ctx->teedev->priv;
    long ret = 0;
​
    switch (cmd) {
    case TEE_IOC_OPEN_SESSION:
        ret = tee_ioctl_open_session(ctx, arg);
        break;
    case TEE_IOC_CLOSE_SESSION:
        ret = tee_ioctl_close_session(ctx, arg);
        break;
    case TEE_IOC_INVOKE_COMMAND:
        ret = tee_ioctl_invoke_command(ctx, arg);
        break;
    case TEE_IOC_SHM_ALLOC:
        ret = tee_ioctl_shm_alloc(ctx, arg);
        break;
    case TEE_IOC_SHM_FREE:
        ret = tee_ioctl_shm_free(ctx, arg);
        break;
    default:
        ret = -ENOTTY;
        break;
    }
​
    return ret;
}

4.4 软件设计模式树形分析

TrustZone/TEE 设计模式
├── 工厂模式 (Factory Pattern)
│   ├── tee_device_alloc():创建 TEE 设备
│   └── tee_shm_alloc():创建共享内存
├── 适配器模式 (Adapter Pattern)
│   ├── optee_smc_call():适配 SMC 调用
│   └── tee_ioctl():适配 ioctl 命令
├── 策略模式 (Strategy Pattern)
│   ├── optee_handle_cmd():命令处理策略
│   └── tee_shm_alloc():共享内存分配策略
├── 观察者模式 (Observer Pattern)
│   ├── tee_invoke_command():观察命令完成事件
│   └── optee_probe():观察设备探测事件
├── 状态模式 (State Pattern)
│   └── 会话状态 (OPEN/CLOSED/INVOKING)
└── 模板方法模式 (Template Method Pattern)
    └── tee_invoke_command():定义了 TEE 命令调用的标准流程

4.5 TrustZone 调试核心难点

4.5.1 SMC 调用失败

现象optee_smc_call 返回 SMC_ERROR,TEE 操作失败。

原因

  1. SMC 参数错误。

  2. 安全世界未正常启动。

  3. 权限不足。

调试方法

  1. 使用 trace-cmd record -e smc:* 跟踪 SMC 调用。

  2. 检查 dmesg | grep tee 查看 TEE 日志。

  3. 使用 xtest 测试 TEE 功能。

4.5.2 共享内存分配失败

现象tee_shm_alloc 返回 -ENOMEM,无法分配共享内存。

原因

  1. 内存池耗尽。

  2. 页面分配失败。

  3. DMA 映射失败。

调试方法

  1. 检查 tee_shm_pool 配置。

  2. 使用 cat /sys/kernel/debug/tee/shm 查看共享内存统计。

  3. 检查 DMA 配置。

4.5.3 TEE 会话无法创建

现象tee_session_create 返回 -EIO,无法创建 TEE 会话。

原因

  1. 可信应用未加载。

  2. 会话 ID 冲突。

  3. OP-TEE 内核未响应。

调试方法

  1. 检查 tee_session 日志。

  2. 使用 cat /proc/sys/tee/ta_ids 查看已加载 TA。

  3. 重启 TEE 设备:rmmod optee; modprobe optee

4.6 与其他模块的协同

模块 协同方式 调试关键点
SMC 调用 通过 SMC 与安全世界通信 参数传递、结果返回
共享内存 TEE 与非安全世界交换数据 页面分配、DMA 映射
设备驱动 提供 TEE 设备接口 设备节点、ioctl
进程管理 管理 TEE 会话 会话创建、关闭
内存管理 管理共享内存 页面池、DMA 地址
用户空间 通过 TEE 客户端 API 访问 信任应用、命令调用

第五部分 内核调试核心工具链

5.1 调试工具链全景

Linux 内核调试是系统开发中最具挑战性的任务之一。Ftrace、Perf、eBPF 和 Systrace 是四款最强大的内核调试工具,它们从不同维度提供了对内核行为的深入洞察。

5.1.1 调试工具对比

工具 核心功能 适用场景 性能开销 学习曲线
Ftrace 函数追踪、事件追踪、延迟分析 内核函数调用、中断延迟、调度延迟 中等
Perf 硬件性能计数器、采样分析、统计分析 CPU 性能分析、缓存 miss 分析 低-中 较高
eBPF 动态追踪、过滤、统计、安全监控 自定义追踪、实时监控、安全策略
Systrace 系统级事件追踪、UI 性能分析 Android 系统性能、UI 流畅度 中等

5.1.2 工具链架构

[Ftrace]
    ├── /sys/kernel/debug/tracing/
    │   ├── trace → 追踪输出
    │   ├── trace_marker → 用户空间标记
    │   ├── current_tracer → 选择追踪器
    │   └── trace_options → 追踪选项
    ↓
[Perf]
    ├── perf record → 采样记录
    ├── perf report → 报告生成
    ├── perf stat → 性能统计
    └── perf probe → 动态探测
    ↓
[eBPF]
    ├── bpf_prog_load() → 加载 BPF 程序
    ├── bpf_map_create() → 创建 BPF 映射
    ├── bpf_attach_kprobe() → 挂载 kprobe
    └── bpf_trace_printk() → 打印追踪信息
    ↓
[Systrace]
    ├── atrace → 抓取 Android 追踪
    ├── systrace.py → 生成 HTML 报告
    └── perfetto → 新一代追踪工具

5.2 核心代码实现

5.2.1 Ftrace 基本使用 (代码出处: kernel/trace/)

# 代码出处: kernel/trace/
​
# 1. 启用函数追踪
echo function > /sys/kernel/debug/tracing/current_tracer
​
# 2. 设置追踪函数过滤 (只追踪特定函数)
echo "__do_kern_addr" > /sys/kernel/debug/tracing/set_ftrace_filter
​
# 3. 开始追踪
echo 1 > /sys/kernel/debug/tracing/tracing_on
​
# 4. 执行测试操作
# ... 触发追踪事件 ...
​
# 5. 停止追踪
echo 0 > /sys/kernel/debug/tracing/tracing_on
​
# 6. 查看追踪结果
cat /sys/kernel/debug/tracing/trace

5.2.2 Perf 基本使用 (代码出处: tools/perf/)

# 代码出处: tools/perf/
​
# 1. 记录 CPU 性能事件
perf record -e cycles -e instructions -e cache-misses \
  -p $(pgrep audioserver) -- sleep 5
​
# 2. 生成报告
perf report --stdio --sort=symbol
​
# 3. 实时查看性能统计
perf stat -e cycles,instructions,branch-misses \
  -p $(pgrep audioserver) -- sleep 2
​
# 4. 动态探测函数
perf probe --add 'do_sys_open filename=+0(%di):string'
​
# 5. 追踪函数调用
perf record -e probe:do_sys_open -a -- sleep 5

5.2.3 eBPF 程序示例 (代码出处: samples/bpf/)

// 代码出处: samples/bpf/trace_event_kern.c
​
/**
 * @brief eBPF 程序:跟踪 open 系统调用。
 */
SEC("kprobe/sys_open")
int bpf_trace_open(struct pt_regs *ctx)
{
    char filename[256];
    u32 pid = bpf_get_current_pid_tgid() >> 32;
    u32 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
​
    // 1. 获取文件名
    bpf_probe_read_user_str(filename, sizeof(filename),
                           (void *)ctx->di);
​
    // 2. 输出追踪信息
    bpf_trace_printk("open: pid=%d uid=%d file=%s\n", pid, uid, filename);
​
    return 0;
}
​
/**
 * @brief eBPF 程序:统计系统调用次数。
 */
SEC("tracepoint/syscalls/sys_enter_openat")
int bpf_trace_sys_openat(struct trace_event_raw_sys_enter *ctx)
{
    u64 key = ctx->id;
    u64 *value;
​
    // 1. 查找统计映射
    value = bpf_map_lookup_elem(&syscall_map, &key);
    if (!value) {
        // 首次调用,初始化计数
        u64 init_val = 1;
        bpf_map_update_elem(&syscall_map, &key, &init_val, BPF_ANY);
        return 0;
    }
​
    // 2. 更新计数
    (*value)++;
    bpf_map_update_elem(&syscall_map, &key, value, BPF_ANY);
​
    return 0;
}
​
// 定义 BPF 映射
struct bpf_map_def SEC("maps") syscall_map = {
    .type = BPF_MAP_TYPE_HASH,
    .key_size = sizeof(u64),
    .value_size = sizeof(u64),
    .max_entries = 1024,
};
​
char _license[] SEC("license") = "GPL";

5.2.4 eBPF 程序加载与运行 (代码出处: samples/bpf/trace_event_user.c)

// 代码出处: samples/bpf/trace_event_user.c
​
/**
 * @brief 加载并运行 BPF 程序。
 * @return 0 成功,负数错误
 */
static int bpf_trace_run(void)
{
    struct bpf_object *obj;
    struct bpf_program *prog;
    struct bpf_map *map;
    u64 key, value;
    int prog_fd, map_fd, ret;
​
    // 1. 加载 BPF 目标文件
    obj = bpf_object__open_file("trace_event_kern.o", NULL);
    if (IS_ERR(obj)) {
        return PTR_ERR(obj);
    }
​
    // 2. 加载 BPF 程序
    ret = bpf_object__load(obj);
    if (ret < 0) {
        bpf_object__close(obj);
        return ret;
    }
​
    // 3. 获取程序文件描述符
    prog = bpf_object__find_program_by_name(obj, "bpf_trace_open");
    if (!prog) {
        ret = -ENOENT;
        goto out;
    }
    prog_fd = bpf_program__fd(prog);
​
    // 4. 获取映射文件描述符
    map = bpf_object__find_map_by_name(obj, "syscall_map");
    if (!map) {
        ret = -ENOENT;
        goto out;
    }
    map_fd = bpf_map__fd(map);
​
    // 5. 挂载 kprobe
    ret = bpf_prog_attach(prog_fd, get_kprobe_events(), 0);
    if (ret < 0) {
        goto out;
    }
​
    // 6. 读取统计信息
    printf("System call statistics:\n");
    for (int i = 0; i < 1024; i++) {
        key = i;
        if (bpf_map_lookup_elem(map_fd, &key, &value) == 0) {
            printf("  syscall %llu: %llu\n", key, value);
        }
    }
​
out:
    bpf_object__close(obj);
    return ret;
}

5.2.5 Systrace 使用示例 (代码出处: tools/atrace/)

# 代码出处: tools/atrace/
​
# 1. 启用 Systrace (Android 8.0+)
adb shell atrace --async-start -t 5 -b 40960 \
  gfx input view wm am binder kernel sched freq
​
# 2. 等待 5 秒
​
# 3. 停止并获取追踪数据
adb shell atrace --async-stop
adb pull /sys/kernel/debug/tracing/trace
​
# 4. 生成 HTML 报告
python systrace.py --from-file trace
​
# 5. 使用 Perfetto (新一代工具)
adb shell perfetto -c -f -t 5 \
  -o /data/misc/perfetto/trace \
  --txt -s power/regulators
​
adb pull /data/misc/perfetto/trace

5.2.6 Ftrace 高级使用 (代码出处: kernel/trace/trace.c)

// 代码出处: kernel/trace/trace.c
​
/**
 * @brief 设置 Ftrace 追踪过滤器。
 * @param tr 追踪器指针
 * @param filter_str 过滤器字符串
 * @return 0 成功,负数错误
 */
static int trace_set_filter(struct trace_ops *tr, const char *filter_str)
{
    struct trace_filter *filter;
    struct trace_filter_ops *filter_ops;
    int ret;
​
    // 1. 分配过滤器
    filter = kmalloc(sizeof(*filter), GFP_KERNEL);
    if (!filter) {
        return -ENOMEM;
    }
​
    // 2. 解析过滤器
    ret = trace_filter_parse(filter, filter_str);
    if (ret < 0) {
        kfree(filter);
        return ret;
    }
​
    // 3. 设置过滤器
    filter_ops = tr->filter_ops;
    ret = filter_ops->set_filter(tr, filter);
    if (ret < 0) {
        kfree(filter);
        return ret;
    }
​
    return 0;
}
​
/**
 * @brief 用户空间标记事件。
 * @param fmt 格式字符串
 * @return 0 成功,负数错误
 */
int trace_mark(const char *fmt, ...)
{
    va_list args;
    char buf[256];
    int len;
    int ret;
​
    // 1. 格式化字符串
    va_start(args, fmt);
    len = vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);
​
    // 2. 写入 trace_marker
    ret = __trace_puts(buf, len);
    if (ret < 0) {
        return ret;
    }
​
    return 0;
}
EXPORT_SYMBOL(trace_mark);

5.3 软件设计模式树形分析

调试工具链设计模式
├── 工厂模式 (Factory Pattern)
│   ├── bpf_object__open_file():创建 BPF 对象
│   └── trace_set_filter():创建追踪过滤器
├── 适配器模式 (Adapter Pattern)
│   ├── bpf_prog_attach():适配 BPF 程序到 kprobe
│   └── perf_event_open():适配 perf 事件
├── 观察者模式 (Observer Pattern)
│   ├── bpf_trace_open():观察 open 系统调用
│   └── perf_event_reader():观察 perf 事件
├── 策略模式 (Strategy Pattern)
│   ├── ftrace_ops:追踪策略
│   └── bpf_map_lookup_elem():映射查找策略
└── 模板方法模式 (Template Method Pattern)
    └── bpf_trace_run():定义了 BPF 程序加载的标准流程

5.4 调试工具链调试核心难点

5.4.1 Ftrace 输出过多

现象cat /sys/kernel/debug/tracing/trace 输出过多信息。

原因

  1. 未设置过滤器。

  2. 追踪函数过多。

  3. 追踪持续时间过长。

调试方法

  1. 设置过滤器:echo "do_sys_open" > set_ftrace_filter

  2. 限制追踪时间:echo 1 > tracing_on; sleep 1; echo 0 > tracing_on

  3. 使用 set_ftrace_notrace 排除不需要的函数。

5.4.2 eBPF 验证失败

现象:加载 eBPF 程序时返回 -EINVAL

原因

  1. 程序违反 eBPF 验证器规则。

  2. 循环或分支过多。

  3. 内存访问越界。

调试方法

  1. 使用 bpf_object__load 的日志输出。

  2. 简化程序逻辑。

  3. 使用 bpf_get_stack 等安全函数。

5.4.3 Perf 采样过高

现象perf record 导致系统负载飙升。

原因

  1. 采样频率过高。

  2. 追踪事件过多。

  3. 缓冲区太小。

调试方法

  1. 降低采样频率:perf record -F 100

  2. 减少追踪事件。

  3. 增大缓冲区:perf record -m 64

5.5 与其他模块的协同

模块 协同方式 调试关键点
内核函数 通过 ftrace 追踪函数调用 函数入口/出口、调用栈
硬件性能 通过 perf 监控硬件事件 缓存 miss、分支预测
系统调用 通过 eBPF 追踪系统调用 系统调用参数、返回值
进程管理 追踪进程调度事件 调度延迟、负载均衡
内存管理 追踪内存分配事件 内存泄漏、页面分配
设备驱动 通过 kprobe 跟踪驱动函数 设备操作、中断处理

第六部分 内核崩溃分析

6.1 内核崩溃核心概念

内核崩溃 (Kernel Panic) 是 Linux 内核遇到无法恢复的错误时触发的紧急状态。当内核崩溃时,系统会停止所有活动并打印诊断信息。对于 ARM64 平台和 Android 系统,正确分析和定位内核崩溃是 BSP 开发中最关键的技能之一。

6.1.1 Oops 与 Panic 的对比

特性 Oops Panic
严重程度 可恢复 (但可能不稳定) 不可恢复
触发条件 非法内存访问、空指针引用 严重错误、内核死锁
系统状态 可能继续运行 立即停止
日志输出 部分寄存器/栈信息 完整寄存器/栈信息
调试难度 中等 较高
处理方式 可加载模块卸载 需要系统重启

6.1.2 崩溃信息结构

[Kernel Panic 日志]
    ├── [CPU 状态]
    │   ├── 异常类型 (Synchronous/Asynchronous)
    │   ├── 异常级别 (EL0/EL1/EL2/EL3)
    │   ├── 异常地址 (Fault Address)
    │   └── 异常指令 (Instruction Fault)
    ├── [寄存器状态]
    │   ├── 通用寄存器 (X0-X30)
    │   ├── 栈指针 (SP)
    │   ├── 程序计数器 (PC)
    │   └── 状态寄存器 (PSTATE)
    ├── [栈回溯]
    │   ├── 栈帧 (Stack Frame)
    │   ├── 函数调用链 (Call Chain)
    │   └── 符号解析 (Symbol Resolution)
    └── [内存状态]
        ├── 页面映射 (Page Mapping)
        ├── SLAB 缓存信息
        └── 内存统计

6.2 核心数据结构

6.2.1 崩溃记录结构 (代码出处: kernel/panic.c)

// 代码出处: kernel/panic.c
​
/**
 * @struct panic_info
 * @brief 内核崩溃信息结构。
 */
struct panic_info {
    unsigned long panic_flags;              /**< 崩溃标志 */
    unsigned long panic_cpu;                /**< 发生崩溃的 CPU */
    unsigned long panic_time;               /**< 崩溃时间 (秒) */
    const char *panic_message;              /**< 崩溃消息 */
    void *caller;                           /**< 调用者地址 */
    struct pt_regs *regs;                   /**< 寄存器状态 */
    struct task_struct *task;               /**< 当前任务 */
    struct list_head *stack_trace;          /**< 栈回溯列表 */
    struct list_head *mm;                   /**< 内存描述符 */
    struct list_head *regions;              /**< 内存区域 */
};
​
/**
 * @struct crash_info
 * @brief 崩溃信息结构。
 */
struct crash_info {
    struct panic_info panic;                /**< 崩溃信息 */
    struct timeval timestamp;               /**< 时间戳 */
    char module_name[64];                   /**< 模块名称 */
    char function_name[64];                 /**< 函数名称 */
    unsigned long instruction_pointer;      /**< 指令指针 */
    unsigned long stack_pointer;            /**< 栈指针 */
    unsigned long link_register;            /**< 链接寄存器 */
    unsigned long fault_address;            /**< 错误地址 */
    unsigned long error_code;               /**< 错误码 */
    struct list_head *stack_frames;         /**< 栈帧列表 */
    struct list_head *symbols;              /**< 符号列表 */
};

6.3 核心代码实现

6.3.1 崩溃触发与处理 (代码出处: kernel/panic.c)

// 代码出处: kernel/panic.c
​
/**
 * @brief 触发内核崩溃。
 * @param fmt 格式字符串
 * @param ... 参数
 */
void panic(const char *fmt, ...)
{
    static char buf[1024];
    va_list args;
    int ret;
​
    // 1. 格式化消息
    va_start(args, fmt);
    ret = vsnprintf(buf, sizeof(buf), fmt, args);
    va_end(args);
​
    // 2. 打印崩溃信息
    pr_emerg("Kernel panic - not syncing: %s\n", buf);
​
    // 3. 禁止抢占
    preempt_disable();
​
    // 4. 记录崩溃信息
    panic_record(&panic_info);
​
    // 5. 触发 kdump
    crash_kexec(NULL);
​
    // 6. 进入无限循环
    while (1) {
        // 等待重启
        if (panic_timeout > 0) {
            schedule_timeout(panic_timeout * HZ);
            // 触发重启
            restart_handler();
        }
        cpu_relax();
    }
}
EXPORT_SYMBOL(panic);
​
/**
 * @brief 处理 Oops。
 * @param regs 寄存器状态
 * @param error_code 错误码
 * @param address 错误地址
 */
void __weak show_stack(struct task_struct *task, struct list_head *stack)
{
    struct stack_frame *frame;
    unsigned long pc, lr;
    struct list_head *stack_list;
​
    // 1. 检查是否有栈
    if (!task) {
        task = current;
    }
​
    // 2. 获取栈指针
    stack_list = task->stack;
    if (!stack_list) {
        return;
    }
​
    // 3. 遍历栈帧
    list_for_each_entry(frame, stack_list, list) {
        pc = frame->pc;
        lr = frame->lr;
​
        // 4. 打印栈帧信息
        pr_emerg("  %*pS\n", 12, (void *)pc);
        if (frame->lr != 0) {
            pr_emerg("  LR = %pS\n", (void *)lr);
        }
​
        // 5. 检查是否到达栈顶
        if (frame->prev == NULL) {
            break;
        }
    }
}

6.3.2 Kdump 配置与使用 (代码出处: arch/arm64/kernel/crash_dump.c)

// 代码出处: arch/arm64/kernel/crash_dump.c
​
/**
 * @brief 初始化 kdump。
 * @return 0 成功,负数错误
 */
static int crash_dump_init(void)
{
    struct crash_info *info;
    int ret;
​
    // 1. 分配崩溃信息结构
    info = kzalloc(sizeof(*info), GFP_KERNEL);
    if (!info) {
        return -ENOMEM;
    }
​
    // 2. 初始化崩溃信息
    info->panic.panic_flags = 0;
    info->panic.panic_cpu = 0;
    info->panic.panic_time = 0;
    info->panic.panic_message = NULL;
    info->panic.caller = NULL;
    info->panic.regs = NULL;
    info->panic.task = NULL;
    info->panic.stack_trace = NULL;
    info->panic.mm = NULL;
    info->panic.regions = NULL;
​
    // 3. 注册崩溃钩子
    ret = register_crash_handler(crash_handler, info);
    if (ret < 0) {
        kfree(info);
        return ret;
    }
​
    // 4. 创建崩溃文件
    crash_file = debugfs_create_file("crash", 0444, NULL, info, &crash_fops);
​
    return 0;
}
​
/**
 * @brief 内核崩溃处理函数。
 * @param info 崩溃信息
 * @param regs 寄存器状态
 * @param error_code 错误码
 * @param address 错误地址
 */
static void crash_handler(struct crash_info *info, struct pt_regs *regs,
                          unsigned long error_code, unsigned long address)
{
    // 1. 保存寄存器
    info->regs = regs;
    info->error_code = error_code;
    info->fault_address = address;
​
    // 2. 保存当前任务
    info->task = current;
​
    // 3. 保存栈回溯
    info->stack_frames = get_stack_frames(regs);
​
    // 4. 保存内存信息
    info->mm = current->mm;
    info->regions = get_memory_regions();
​
    // 5. 触发 kdump
    crash_kexec(NULL);
}
​
/**
 * @brief 触发 kdump。
 * @param image 内核镜像指针
 * @return 0 成功,负数错误
 */
int crash_kexec(struct kimage *image)
{
    struct kexec_control_block *cb;
    int ret;
​
    // 1. 获取控制块
    cb = kexec_get_control_block();
    if (!cb) {
        return -ENOMEM;
    }
​
    // 2. 设置崩溃信息
    cb->info = &panic_info;
​
    // 3. 启动 kdump
    ret = kexec_load(image, 0, 0);
    if (ret < 0) {
        return ret;
    }
​
    // 4. 执行 kdump
    ret = kexec_start(image);
    if (ret < 0) {
        return ret;
    }
​
    return 0;
}

6.3.3 Crash 工具基本使用

# 1. 安装 crash 工具
sudo apt-get install crash
​
# 2. 获取 vmcore
# 启用 kdump: 修改 /etc/default/grub
# GRUB_CMDLINE_LINUX="crashkernel=512M"
# update-grub
​
# 3. 触发崩溃 (测试)
# echo c > /proc/sysrq-trigger
​
# 4. 分析 vmcore
crash /usr/lib/debug/vmlinux /var/crash/2025-01-01/vmcore
​
# 5. Crash 常用命令
crash> bt  # 栈回溯
crash> log # 查看内核日志
crash> ps  # 查看进程列表
crash> task  # 查看任务结构
crash> kmem  # 内存统计
crash> files # 查看打开的文件

6.3.4 Crash 工具高级分析

# 1. 定位崩溃点
crash> bt
PID: 1234  TASK: ffff800012345678  CPU: 0  COMMAND: "app_process"
 #0 [ffff800012345678]  do_sys_open+0x14/0x20
 #1 [ffff800012345678]  sys_open+0x18/0x28
 #2 [ffff800012345678]  el0_svc_naked+0x38/0x50
​
# 2. 检查寄存器
crash> regs
  x0: 0x0000000000000001  x1: 0xffff800012345678  x2: 0x0000000000000000
  x3: 0x0000000000000000  x4: 0x0000000000000000  x5: 0x0000000000000000
  x6: 0x0000000000000000  x7: 0x0000000000000000  x8: 0xffff800012345678
  x9: 0x0000000000000000  x10: 0x0000000000000000  x11: 0x0000000000000000
  x12: 0x0000000000000000  x13: 0x0000000000000000  x14: 0x0000000000000000
  x15: 0x0000000000000000  x16: 0x0000000000000000  x17: 0x0000000000000000
  x18: 0x0000000000000000  x19: 0xffff800012345678  x20: 0x0000000000000000
  x21: 0x0000000000000000  x22: 0x0000000000000000  x23: 0x0000000000000000
  x24: 0x0000000000000000  x25: 0x0000000000000000  x26: 0x0000000000000000
  x27: 0x0000000000000000  x28: 0x0000000000000000  x29: 0x0000000000000000
  x30: 0x0000000000000000  sp: 0xffff800012345678  pc: 0xffff800012345678
​
# 3. 分析内存
crash> kmem -i
  total       used       free       shared    buffers   cached
  Mem:  2048M      1024M      1024M      512M      256M      512M
  -/+ buffers/cache: 256M 1792M
  Swap:  0M      0M      0M
​
# 4. 查看堆栈
crash> stack
  SP: 0xffff800012345678  PC: 0xffff800012345678
  #0: 0xffff800012345678
  #1: 0xffff800012345678
  #2: 0xffff800012345678
​
# 5. 分析某个进程
crash> task 1234
  PID: 1234  TASK: ffff800012345678  CPU: 0  COMMAND: "app_process"
  STATE: RUNNING  PPID: 123  PRI: 120
  VM: 0xffff800012345678
  MM: 0xffff800012345678
  FS: 0xffff800012345678

6.3.5 崩溃日志分析示例

# 1. 获取崩溃日志
dmesg | grep "Kernel panic"
[ 1234.567890] Kernel panic - not syncing: Fatal exception
[ 1234.567890] CPU: 0 PID: 1234 Comm: app_process Not tainted 5.10.0-rc1+
[ 1234.567890] Hardware name: Rockchip RK3399 (DT)
[ 1234.567890] pc : do_sys_open+0x14/0x20
[ 1234.567890] lr : sys_open+0x18/0x28
[ 1234.567890] sp : ffff800012345678
[ 1234.567890] x29: ffff800012345678 x28: ffff800012345678
[ 1234.567890] x27: ffff800012345678 x26: ffff800012345678
[ 1234.567890] x25: ffff800012345678 x24: ffff800012345678
[ 1234.567890] x23: ffff800012345678 x22: ffff800012345678
[ 1234.567890] x21: ffff800012345678 x20: ffff800012345678
[ 1234.567890] x19: ffff800012345678 x18: ffff800012345678
[ 1234.567890] x17: ffff800012345678 x16: ffff800012345678
[ 1234.567890] x15: ffff800012345678 x14: ffff800012345678
[ 1234.567890] x13: ffff800012345678 x12: ffff800012345678
[ 1234.567890] x11: ffff800012345678 x10: ffff800012345678
[ 1234.567890] x9 : ffff800012345678 x8 : ffff800012345678
[ 1234.567890] x7 : ffff800012345678 x6 : ffff800012345678
[ 1234.567890] x5 : ffff800012345678 x4 : ffff800012345678
[ 1234.567890] x3 : ffff800012345678 x2 : ffff800012345678
[ 1234.567890] x1 : ffff800012345678 x0 : ffff800012345678
​
# 2. 分析栈回溯
[ 1234.567890] Call trace:
[ 1234.567890]  do_sys_open+0x14/0x20
[ 1234.567890]  sys_open+0x18/0x28
[ 1234.567890]  el0_svc_naked+0x38/0x50
[ 1234.567890]  el0_svc_handler+0x30/0x40
[ 1234.567890]  el0_svc_common+0x18/0x20
​
# 3. 分析错误地址
[ 1234.567890]  fault_address: 0xffff800012345678
[ 1234.567890]  error_code: 0x1 (Translation fault)
​
# 4. 分析内存信息
[ 1234.567890]  Page: 0xffff800012345678
[ 1234.567890]  PTE: 0xffff800012345678
[ 1234.567890]  Phys: 0xffff800012345678
​
# 5. 定位问题
# 错误地址 0xffff800012345678 在内核态,指向一个无效的内存区域
# 翻译错误 (Translation fault) 表示页表无法解析该地址
# 需要检查 do_sys_open 函数的参数,是否传递了无效的文件名指针

6.4 软件设计模式树形分析

内核崩溃分析设计模式
├── 观察者模式 (Observer Pattern)
│   ├── panic():观察系统崩溃事件
│   └── crash_handler():观察崩溃信号
├── 工厂模式 (Factory Pattern)
│   ├── crash_dump_init():创建 kdump 实例
│   └── crash_info_alloc():创建崩溃信息结构
├── 策略模式 (Strategy Pattern)
│   ├── crash_kexec():崩溃处理策略
│   └── show_stack():栈回溯策略
├── 适配器模式 (Adapter Pattern)
│   ├── crash_file_fops:适配 debugfs 接口
│   └── crash_vmcore_ops:适配 vmcore 接口
└── 模板方法模式 (Template Method Pattern)
    └── panic():定义了内核崩溃的标准处理流程

6.5 内核崩溃调试核心难点

6.5.1 空指针引用

现象:内核崩溃日志显示 Translation faultpc 指向某个函数,lr 指向上层调用。

原因

  1. 对空指针进行解引用。

  2. 释放后使用。

  3. 指针未初始化。

调试方法

  1. 检查 x0 寄存器的值。

  2. 使用 crash 查看调用栈。

  3. 查看 do_sys_open 函数参数。

6.5.2 栈溢出

现象:内核崩溃日志显示 stack overflowsp 指向栈底。

原因

  1. 递归调用过深。

  2. 栈缓冲区过大。

  3. 栈大小配置不足。

调试方法

  1. 检查栈指针。

  2. 查看栈帧数量。

  3. 增加栈大小。

6.5.3 内存踩踏

现象:内核崩溃随机发生,错误地址不稳定。

原因

  1. 越界写。

  2. 缓冲区溢出。

  3. 内存破坏。

调试方法

  1. 使用 kmemleak 检测内存泄漏。

  2. 使用 slub_debug 检测内存破坏。

  3. 使用 kasan 动态检测。

6.6 与其他模块的协同

模块 协同方式 调试关键点
内存管理 提供内存信息 页面状态、SLAB 缓存
进程管理 提供任务信息 进程状态、栈信息
调度器 提供调度信息 任务上下文、CPU 状态
中断控制器 提供中断信息 中断号、中断状态
设备驱动 提供设备信息 设备状态、寄存器信息

第七部分 汇编/反汇编基础

7.1 ARM64 汇编基础

ARM64 (AArch64) 是 ARM 架构的 64 位指令集,广泛应用于移动设备、服务器和嵌入式系统。理解 ARM64 汇编是定位内核崩溃、分析性能瓶颈和进行底层调试的关键技能。

7.1.1 ARM64 寄存器

寄存器 用途 调用约定 保留
X0-X7 参数传递、返回值 参数寄存器
X8 间接结果位置 返回地址
X9-X15 临时变量 调用者保存
X16-X17 临时变量 (IP0/IP1) 调用者保存
X18 平台保留 平台保留
X19-X28 临时变量 被调用者保存
X29 帧指针 (FP) 被调用者保存
X30 链接寄存器 (LR) 被调用者保存
SP 栈指针 被调用者保存
PC 程序计数器
PSTATE 处理器状态

7.1.2 ARM64 指令格式

指令类型 格式 示例
数据处理 op dst, src1, src2 add x0, x1, x2
加载/存储 op dst, [base, offset] ldr x0, [x1, #8]
跳转 op target bl do_sys_open
比较 op src1, src2 cmp x0, x1
条件跳转 op target b.eq 0xffff800012345678

7.1.3 ARM64 函数调用约定

[函数调用流程]
    ↓
1. 保存 LR 到栈 (如果调用其他函数)
2. 保存 FP 到栈
3. 分配栈空间 (sp -= size)
4. 将参数从 X0-X7 移动到局部变量
5. 执行函数体
6. 将返回值放在 X0
7. 恢复栈空间 (sp += size)
8. 恢复 FP
9. 跳转到 LR (ret)

7.2 反汇编基础

7.2.1 反汇编工具

工具 用途 命令示例
objdump 反汇编二进制文件 objdump -d vmlinux
gdb 动态反汇编 gdb vmlinux; disassemble do_sys_open
perf 实时反汇编 perf record -e cycles -a -- sleep 5; perf report
crash 内核崩溃反汇编 crash vmlinux vmcore; disassemble 0xffff800012345678
llvm-objdump LLVM 反汇编器 llvm-objdump -d vmlinux

7.2.2 栈帧分析

// 代码出处: arch/arm64/kernel/process.c
​
/**
 * @brief 栈帧结构。
 */
struct stack_frame {
    struct stack_frame *prev;       /**< 上一个栈帧 */
    unsigned long lr;               /**< 链接寄存器 */
    unsigned long pc;               /**< 程序计数器 */
    unsigned long fp;               /**< 帧指针 */
    unsigned long sp;               /**< 栈指针 */
};
​
/**
 * @brief 打印栈回溯。
 * @param regs 寄存器状态
 * @param task 任务指针
 */
void show_stack(struct task_struct *task, unsigned long *sp)
{
    struct stack_frame *frame;
    unsigned long pc, lr;
    int i = 0;
​
    // 1. 检查是否有栈
    if (!task) {
        task = current;
    }
    if (!sp) {
        sp = task->stack;
    }
​
    // 2. 遍历栈帧
    while (sp) {
        frame = (struct stack_frame *)sp;
        pc = frame->pc;
        lr = frame->lr;
​
        // 3. 打印栈帧
        pr_emerg("  %*pS\n", 12, (void *)pc);
        if (lr != 0) {
            pr_emerg("  LR = %pS\n", (void *)lr);
        }
​
        // 4. 移动到下一个栈帧
        sp = frame->prev;
        i++;
        if (i > 100) {
            break;
        }
    }
}

7.3 核心代码实现

7.3.1 反汇编内核函数

# 1. 获取内核符号表
nm vmlinux | grep do_sys_open
ffff800012345678 T do_sys_open
​
# 2. 反汇编 do_sys_open
objdump -d vmlinux | grep -A 20 "do_sys_open"
ffff800012345678 <do_sys_open>:
ffff800012345678:  stp x29, x30, [sp, #-32]!
ffff80001234567c:  mov x29, sp
ffff800012345680:  str x19, [sp, #16]
ffff800012345684:  mov w19, w0
ffff800012345688:  mov w0, w1
ffff80001234568c:  bl ffff800012345678 <do_sys_open>
ffff800012345690:  mov w0, w19
ffff800012345694:  ldp x19, x29, [sp, #16]
ffff800012345698:  ldp x29, x30, [sp], #32
ffff80001234569c:  ret
​
# 3. 使用 gdb 反汇编
gdb vmlinux
(gdb) disassemble do_sys_open
Dump of assembler code for function do_sys_open:
   0xffff800012345678 <+0>:  stp x29, x30, [sp, #-32]!
   0xffff80001234567c <+4>:  mov x29, sp
   0xffff800012345680 <+8>:  str x19, [sp, #16]
   0xffff800012345684 <+12>: mov w19, w0
   0xffff800012345688 <+16>: mov w0, w1
   0xffff80001234568c <+20>: bl 0xffff800012345678 <do_sys_open>
   0xffff800012345690 <+24>: mov w0, w19
   0xffff800012345694 <+28>: ldp x19, x29, [sp, #16]
   0xffff800012345698 <+32>: ldp x29, x30, [sp], #32
   0xffff80001234569c <+36>: ret
End of assembler dump.

7.3.2 崩溃点定位

# 1. 假设崩溃点在 0xffff80001234568c
crash> bt
PID: 1234  TASK: ffff800012345678  CPU: 0  COMMAND: "app_process"
 #0 [ffff800012345678]  do_sys_open+0x14/0x20
 #1 [ffff800012345678]  sys_open+0x18/0x28
 #2 [ffff800012345678]  el0_svc_naked+0x38/0x50
​
# 2. 反汇编 do_sys_open
crash> disassemble do_sys_open
0xffff800012345678 <do_sys_open>:
  stp x29, x30, [sp, #-32]!
  mov x29, sp
  str x19, [sp, #16]
  mov w19, w0
  mov w0, w1
  bl 0xffff800012345678 <do_sys_open>
  mov w0, w19
  ldp x19, x29, [sp, #16]
  ldp x29, x30, [sp], #32
  ret
​
# 3. 计算偏移
# 崩溃点在 0xffff80001234568c,相对于 do_sys_open 的偏移 = 0x14
# 对应指令: bl 0xffff800012345678 <do_sys_open>
​
# 4. 分析指令
# bl 0xffff800012345678 <do_sys_open> 是调用 do_sys_open 自身
# 这是一个递归调用,可能导致栈溢出

7.3.3 寄存器分析

# 1. 查看崩溃时的寄存器
crash> regs
  x0: 0x0000000000000001
  x1: 0x0000000000000002
  x2: 0x0000000000000003
  x3: 0x0000000000000004
  x4: 0x0000000000000005
  x5: 0x0000000000000006
  x6: 0x0000000000000007
  x7: 0x0000000000000008
  x8: 0x0000000000000009
  x9: 0x000000000000000a
  x10: 0x000000000000000b
  x11: 0x000000000000000c
  x12: 0x000000000000000d
  x13: 0x000000000000000e
  x14: 0x000000000000000f
  x15: 0x0000000000000010
  x16: 0x0000000000000011
  x17: 0x0000000000000012
  x18: 0x0000000000000013
  x19: 0x0000000000000014
  x20: 0x0000000000000015
  x21: 0x0000000000000016
  x22: 0x0000000000000017
  x23: 0x0000000000000018
  x24: 0x0000000000000019
  x25: 0x000000000000001a
  x26: 0x000000000000001b
  x27: 0x000000000000001c
  x28: 0x000000000000001d
  x29: 0x000000000000001e
  x30: 0x000000000000001f
  sp: 0x0000000000000020
  pc: 0x0000000000000021
​
# 2. 分析函数参数
# x0-w0 是第一个参数 (filename)
# x1-w1 是第二个参数 (flags)
# 检查 x0 是否为空指针
# 如果 x0 为 0,则可能是空指针引用

7.3.4 栈回溯分析

# 1. 查看栈回溯
crash> bt
PID: 1234  TASK: ffff800012345678  CPU: 0  COMMAND: "app_process"
 #0 [ffff800012345678]  do_sys_open+0x14/0x20
 #1 [ffff800012345678]  sys_open+0x18/0x28
 #2 [ffff800012345678]  el0_svc_naked+0x38/0x50
​
# 2. 查看栈内容
crash> stack
  SP: 0xffff800012345678  PC: 0xffff800012345678
  #0: 0xffff800012345678
  #1: 0xffff800012345678
  #2: 0xffff800012345678
​
# 3. 分析栈帧
# 栈帧大小: 32 字节 (stp x29, x30, [sp, #-32]!)
# 栈帧布局:
#   sp+0: x29 (fp)
#   sp+8: x30 (lr)
#   sp+16: x19 (saved register)
# 崩溃点在 0xffff80001234568c,对应第 4 条指令
# 指令: bl 0xffff800012345678 <do_sys_open>
# 这是一个递归调用,导致栈溢出

7.4 软件设计模式树形分析

汇编/反汇编分析设计模式
├── 观察者模式 (Observer Pattern)
│   ├── show_stack():观察栈帧信息
│   └── regs_dump():观察寄存器状态
├── 工厂模式 (Factory Pattern)
│   ├── stack_frame_alloc():创建栈帧
│   └── crash_info_alloc():创建崩溃信息结构
├── 策略模式 (Strategy Pattern)
│   ├── stack_trace_strategy():栈回溯策略
│   └── crash_dump_strategy():崩溃转储策略
├── 适配器模式 (Adapter Pattern)
│   ├── regs_to_frame():适配寄存器到栈帧
│   └── crash_to_file():适配崩溃信息到文件
└── 模板方法模式 (Template Method Pattern)
    ├── show_stack():定义了栈回溯的标准流程
    └── crash_handler():定义了崩溃处理的标准流程

7.5 反汇编调试核心难点

7.5.1 栈帧对齐问题

现象:栈回溯中 fp 指针不对齐,导致栈帧解析错误。

原因

  1. 编译器优化。

  2. 汇编中未正确保存 fp

  3. 栈空间分配错误。

调试方法

  1. 检查 fp 是否指向正确位置。

  2. 检查 stp x29, x30, [sp, #-32]! 指令。

  3. 使用 -fno-omit-frame-pointer 重新编译。

7.5.2 符号解析失败

现象:崩溃日志中函数名无法解析,显示 [<0xffff800012345678>]

原因

  1. 内核符号表未加载。

  2. 函数被内联。

  3. 调试信息缺失。

调试方法

  1. 使用 nm vmlinux | grep 0xffff800012345678 查找符号。

  2. 使用 objdump -d vmlinux 查看反汇编。

  3. 使用 gdb vmlinux 加载调试信息。

7.6 与其他模块的协同

模块 协同方式 调试关键点
内存管理 提供内存信息 页面状态、堆栈布局
进程管理 提供进程信息 栈指针、任务结构
调试工具 提供反汇编接口 objdumpgdbcrash
编译器 生成调试信息 -g-fno-omit-frame-pointer
内核符号表 提供符号解析 kallsymsSystem.map

第八部分 内核死锁、内存踩踏与野指针问题排查

8.1 三类复杂问题的核心概念

在内核开发中,死锁 (Deadlock)内存踩踏 (Memory Corruption)野指针 (Dangling Pointer) 是最具挑战性的三类问题。它们往往难以复现,且一旦触发可能导致系统崩溃、数据损坏或安全漏洞。

8.1.1 问题对比

问题类型 根本原因 典型症状 检测工具 修复难度
死锁 锁依赖循环、锁顺序错误 系统卡死、CPU 占用 100%、进程阻塞 Lockdep, lock_stat, ftrace 中等
内存踩踏 越界写、缓冲区溢出、use-after-free 数据损坏、随机崩溃、OOM KASAN, SLUB Debug, kmemleak
野指针 指针未初始化、use-after-free 非法内存访问、NULL 指针引用 KASAN, UBSAN, kasan

8.1.2 三类问题的关系图

[内核并发问题]
    ├── [死锁 (Deadlock)]
    │   ├── 互斥锁死锁 (Mutex Deadlock)
    │   ├── 读写锁死锁 (RWSem Deadlock)
    │   ├── 自旋锁死锁 (Spinlock Deadlock)
    │   └── 递归锁死锁 (Recursive Lock Deadlock)
    ├── [内存踩踏 (Memory Corruption)]
    │   ├── 缓冲区溢出 (Buffer Overflow)
    │   ├── 越界写 (Out-of-bounds Write)
    │   ├── Use-after-free
    │   └── 双重释放 (Double Free)
    └── [野指针 (Dangling Pointer)]
        ├── 指针未初始化 (Uninitialized Pointer)
        ├── 释放后使用 (Use-after-free)
        └── 空指针引用 (NULL Pointer Dereference)

8.2 死锁检测与排查

8.2.1 死锁检测工具 (代码出处: lib/locking/lockdep.c)

// 代码出处: lib/locking/lockdep.c
​
/**
 * @struct lockdep_map
 * @brief Lockdep 锁映射结构。
 */
struct lockdep_map {
    struct lock_class_key *key;             /**< 锁类键 */
    struct lock_class *class;               /**< 锁类 */
    const char *name;                       /**< 锁名称 */
    int wait_type_outer;                    /**< 外部等待类型 */
    int wait_type_inner;                    /**< 内部等待类型 */
};
​
/**
 * @brief Lockdep 锁依赖检测。
 * @param lock 锁映射
 * @param ip 调用地址
 * @param nest 嵌套层级
 * @param flags 标志
 */
void lockdep_acquire(struct lockdep_map *lock, unsigned long ip, int nest, int flags)
{
    struct task_struct *curr = current;
    struct lock_class *class = lock->class;
    int i;
​
    // 1. 检查锁是否已持有
    for (i = 0; i < curr->lockdep_depth; i++) {
        if (curr->held_locks[i].class == class) {
            // 重复锁,检查是否允许递归
            if (!class->recursive) {
                lockdep_print_held_locks(curr);
                WARN_ON(1);
            }
            return;
        }
    }
​
    // 2. 检查锁依赖顺序
    if (curr->lockdep_depth > 0) {
        struct lock_class *prev = curr->held_locks[curr->lockdep_depth - 1].class;
        if (lockdep_check_prev(prev, class) < 0) {
            lockdep_print_held_locks(curr);
            WARN_ON(1);
        }
    }
​
    // 3. 记录锁依赖
    curr->held_locks[curr->lockdep_depth].class = class;
    curr->held_locks[curr->lockdep_depth].ip = ip;
    curr->lockdep_depth++;
}
​
/**
 * @brief Lockdep 锁依赖图打印。
 */
void lockdep_print_dependency_graph(void)
{
    struct lock_class *class;
    struct lock_class *dep;
    int i;
​
    pr_info("Lock dependency graph:\n");
    list_for_each_entry(class, &all_lock_classes, lock_entry) {
        pr_info("  %s:\n", class->name);
        for (i = 0; i < class->dep_count; i++) {
            dep = class->deps[i];
            pr_info("    -> %s\n", dep->name);
        }
    }
}

8.2.2 死锁排查流程

# 1. 启用 Lockdep
echo 1 > /proc/sys/kernel/lockdep
echo 1 > /proc/sys/kernel/lockdep_verbose
​
# 2. 触发死锁 (模拟)
# 编写代码造成锁顺序颠倒
​
# 3. 查看 Lockdep 报告
dmesg | grep "possible circular locking dependency detected"
​
# 4. 分析死锁报告
[  123.456789] ======================================================
[  123.456789] [ INFO: possible circular locking dependency detected ]
[  123.456789] 5.10.0-rc1+ #1 Not tainted
[  123.456789] ------------------------------------------------------
[  123.456789] app_process/1234 is trying to acquire lock:
[  123.456789]  (lock_a){+.+.}-{3:3}, at: mutex_lock+0x14/0x20
[  123.456789] 
[  123.456789] but task is already holding lock:
[  123.456789]  (lock_b){+.+.}-{3:3}, at: mutex_lock+0x14/0x20
[  123.456789] 
[  123.456789] which lock already depends on the new lock.
[  123.456789] 
[  123.456789] the existing dependency chain (in reverse order) is:
[  123.456789] 
[  123.456789] -> #1 (lock_b){+.+.}-{3:3}:
[  123.456789]        lock_acquire+0x30/0x40
[  123.456789]        mutex_lock+0x14/0x20
[  123.456789]        do_sys_open+0x14/0x20
[  123.456789]        sys_open+0x18/0x28
[  123.456789]        el0_svc_naked+0x38/0x50
[  123.456789] 
[  123.456789] -> #0 (lock_a){+.+.}-{3:3}:
[  123.456789]        lock_acquire+0x30/0x40
[  123.456789]        mutex_lock+0x14/0x20
[  123.456789]        do_sys_open+0x14/0x20
[  123.456789]        sys_open+0x18/0x28
[  123.456789]        el0_svc_naked+0x38/0x50
[  123.456789] 
[  123.456789] other info that might help us debug this:
[  123.456789] 
[  123.456789] 2 locks held by app_process/1234:
[  123.456789]  #0: (lock_b){+.+.}-{3:3}, at: mutex_lock+0x14/0x20
[  123.456789]  #1: (lock_a){+.+.}-{3:3}, at: mutex_lock+0x14/0x20
​
# 5. 修复建议
# 修改锁顺序,确保 lock_a 在 lock_b 之前获取

8.2.3 死锁避免策略

// 代码出处: kernel/locking/mutex.c
​
/**
 * @brief 死锁避免:获取锁时保持顺序。
 * @param lock_a 第一个锁
 * @param lock_b 第二个锁
 */
void safe_lock_order(struct mutex *lock_a, struct mutex *lock_b)
{
    // 1. 确保 lock_a 在 lock_b 之前获取
    mutex_lock(lock_a);
    mutex_lock(lock_b);
    // ... 临界区代码 ...
    mutex_unlock(lock_b);
    mutex_unlock(lock_a);
}
​
/**
 * @brief 死锁避免:使用锁超时。
 * @param lock 锁指针
 * @param timeout_ms 超时时间 (毫秒)
 * @return 0 成功,-ETIMEDOUT 超时
 */
int try_lock_with_timeout(struct mutex *lock, int timeout_ms)
{
    unsigned long timeout = msecs_to_jiffies(timeout_ms);
    unsigned long start = jiffies;
​
    while (time_before(jiffies, start + timeout)) {
        if (mutex_trylock(lock)) {
            return 0;
        }
        schedule_timeout_uninterruptible(1);
    }
    return -ETIMEDOUT;
}

8.3 内存踩踏检测与排查

8.3.1 KASAN 检测 (代码出处: mm/kasan/kasan.c)

// 代码出处: mm/kasan/kasan.c
​
/**
 * @brief KASAN 内存访问检测。
 * @param addr 访问地址
 * @param size 访问大小
 * @param is_write 是否写操作
 * @param ip 调用地址
 */
void kasan_report(unsigned long addr, size_t size, int is_write, unsigned long ip)
{
    struct kasan_access_info info;
    const char *access_type = is_write ? "write" : "read";
​
    // 1. 检查是否已报告
    if (kasan_suppress_report()) {
        return;
    }
​
    // 2. 构建错误信息
    info.addr = addr;
    info.size = size;
    info.is_write = is_write;
    info.ip = ip;
​
    // 3. 打印错误信息
    pr_err("==================================================================\n");
    pr_err("BUG: KASAN: %s in %pS\n", access_type, (void *)ip);
    pr_err("Address: %pK\n", (void *)addr);
    pr_err("Size: %zu\n", size);
    pr_err("Memory state around the buggy address:\n");
​
    // 4. 打印内存状态
    for (int i = -32; i < 32; i += 8) {
        pr_err("  %pK: %02x\n", (void *)(addr + i), kasan_read_memory_byte(addr + i));
    }
​
    pr_err("==================================================================\n");
​
    // 5. 触发崩溃
    panic("KASAN: memory corruption detected");
}
​
/**
 * @brief KASAN 越界写检测。
 * @param addr 访问地址
 * @param size 访问大小
 * @param is_write 是否写操作
 */
void kasan_check_memory(unsigned long addr, size_t size, int is_write)
{
    unsigned long end = addr + size;
    unsigned long *shadow = kasan_mem_to_shadow(addr);
    unsigned long shadow_end = kasan_mem_to_shadow(end);
​
    // 1. 检查阴影区域
    while (shadow < shadow_end) {
        u8 shadow_val = kasan_read_memory_byte(shadow);
        if (shadow_val != 0) {
            kasan_report(addr, size, is_write, __builtin_return_address(0));
            return;
        }
        shadow++;
    }
}

8.3.2 SLUB Debug 检测 (代码出处: mm/slub.c)

// 代码出处: mm/slub.c
​
/**
 * @brief SLUB 对象生命周期检测。
 * @param object 对象指针
 * @param cache 缓存指针
 */
void slub_debug_object(struct page *page, void *object)
{
    struct kmem_cache *cache = page->slab_cache;
    u8 *page_object = page->slab_cache->object;
    u8 *red_zone = page_object + page->slab_cache->size;
​
    // 1. 检查红色区域 (Red Zone)
    if (*(u8 *)(object + cache->size) != SLUB_RED_ZONE) {
        pr_err("SLUB: Red zone corruption in %s\n", cache->name);
        kasan_report((unsigned long)object, cache->size, 0, __builtin_return_address(0));
    }
​
    // 2. 检查对象状态
    if (*(u8 *)object == SLUB_FREE) {
        // 释放后使用
        pr_err("SLUB: Use-after-free detected in %s\n", cache->name);
        kasan_report((unsigned long)object, cache->size, 0, __builtin_return_address(0));
    }
}
​
/**
 * @brief SLUB 对象分配跟踪。
 * @param cache 缓存指针
 * @param object 对象指针
 * @param caller 调用地址
 */
void slub_alloc_trace(struct kmem_cache *cache, void *object, unsigned long caller)
{
    struct trace_slub *trace = slub_alloc_trace_create(cache, object, caller);
    if (!trace) {
        return;
    }
​
    // 1. 记录分配信息
    trace->cache = cache;
    trace->object = object;
    trace->caller = caller;
    trace->timestamp = jiffies;
    trace->size = cache->size;
​
    // 2. 添加到跟踪列表
    list_add_tail(&trace->list, &slub_trace_list);
}

8.3.3 内存踩踏排查流程

# 1. 启用 KASAN
echo 1 > /proc/sys/kernel/kasan
echo 1 > /proc/sys/kernel/kasan_verbose
​
# 2. 启用 SLUB Debug
echo "slub_debug=P" > /proc/sys/kernel/slub_debug
​
# 3. 执行测试操作
# 触发内存踩踏
​
# 4. 查看 KASAN 报告
dmesg | grep "KASAN"
​
# 5. 分析 KASAN 报告
[  123.456789] ==================================================================
[  123.456789] BUG: KASAN: use-after-free in do_sys_open+0x14/0x20
[  123.456789] Address: ffff800012345678
[  123.456789] Size: 32
[  123.456789] Memory state around the buggy address:
[  123.456789]   ffff800012345678: 0b 0b 0b 0b 0b 0b 0b 0b
[  123.456789]   ffff800012345680: 0b 0b 0b 0b 0b 0b 0b 0b
[  123.456789] ==================================================================
​
# 6. 修复建议
# 检查 do_sys_open 函数的对象生命周期
# 确保使用 kfree 后不再访问对象

8.4 野指针检测与排查

8.4.1 野指针检测工具

# 1. 使用 KASAN 检测野指针
echo 1 > /proc/sys/kernel/kasan
​
# 2. 使用 UBSAN 检测未初始化指针
echo 1 > /proc/sys/kernel/ubsan
​
# 3. 触发野指针 (模拟)
# 编写代码造成 use-after-free
​
# 4. 查看报告
dmesg | grep "UBSAN"
[  123.456789] ==================================================================
[  123.456789] UBSAN: Undefined behavior in do_sys_open+0x14/0x20
[  123.456789] Use of uninitialized pointer in do_sys_open
[  123.456789] ==================================================================
​
# 5. 修复建议
# 检查 do_sys_open 函数中的指针初始化
# 确保指针在使用前已经初始化

8.4.2 野指针排查流程

// 代码出处: lib/ubsan/ubsan.c
​
/**
 * @brief UBSAN 未初始化检测。
 * @param data 未初始化数据
 * @param size 数据大小
 * @param ip 调用地址
 */
void __ubsan_handle_uninitialized(void *data, size_t size, unsigned long ip)
{
    ubsan_report_uninitialized(data, size, ip);
​
    // 1. 打印未初始化的内存内容
    u8 *bytes = (u8 *)data;
    for (int i = 0; i < size; i++) {
        if (bytes[i] != 0x00) {
            pr_err("UBSAN: Uninitialized memory content: 0x%02x\n", bytes[i]);
        }
    }
​
    // 2. 触发崩溃
    panic("UBSAN: uninitialized pointer detected");
}
​
/**
 * @brief UBSAN 空指针引用检测。
 * @param addr 引用地址
 * @param size 引用大小
 * @param ip 调用地址
 */
void __ubsan_handle_null_pointer(void *addr, size_t size, unsigned long ip)
{
    ubsan_report_null_pointer(addr, size, ip);
​
    // 1. 打印空指针信息
    pr_err("UBSAN: Null pointer dereference at %p\n", addr);
​
    // 2. 触发崩溃
    panic("UBSAN: null pointer dereference detected");
}

8.5 综合排查流程

# 1. 启用所有调试工具
echo 1 > /proc/sys/kernel/lockdep
echo 1 > /proc/sys/kernel/kasan
echo 1 > /proc/sys/kernel/ubsan
echo "slub_debug=PF" > /proc/sys/kernel/slub_debug
​
# 2. 执行压力测试
stress --cpu 4 --vm 2 --vm-bytes 512M --timeout 60
​
# 3. 收集所有报告
dmesg | grep -E "(lockdep|KASAN|UBSAN|SLUB)" > /tmp/kernel_issues.log
​
# 4. 分析报告
cat /tmp/kernel_issues.log
​
# 5. 逐项修复
# - 死锁: 调整锁顺序
# - 内存踩踏: 检查缓冲区边界
# - 野指针: 初始化指针

8.6 与其他模块的协同

模块 协同方式 调试关键点
锁管理 提供锁依赖检测 锁顺序、递归锁
内存管理 提供内存分配跟踪 缓冲区边界、对象生命周期
进程管理 提供进程状态信息 进程栈、任务结构
调度器 提供调度信息 任务上下文、CPU 状态
调试工具 提供检测接口 Lockdep、KASAN、UBSAN

第九部分 eBPF 模块编程

9.1 eBPF 核心概念

eBPF (extended Berkeley Packet Filter) 是 Linux 内核中一项革命性的技术,允许在不修改内核代码的情况下,动态加载和执行沙箱化的程序。eBPF 程序可以挂载到内核的各个 hook 点(如 kprobe、tracepoint、系统调用、网络包处理等),实现高性能的数据收集、过滤和监控。

9.1.1 eBPF 架构

[用户空间]
    ├── eBPF 程序源 (.c)
    ├── 编译器 (clang/LLVM) → 生成 BPF 字节码
    ├── libbpf 库 → 加载 BPF 程序
    └── BPF 映射 (Maps) → 内核与用户空间交换数据
    ↓
[内核空间]
    ├── eBPF 验证器 (Verifier)
    │   ├── 检查程序安全性
    │   ├── 检查指令数限制
    │   └── 检查内存访问边界
    ├── eBPF 执行引擎 (JIT)
    │   ├── 将字节码编译为本地指令
    │   └── 提高执行效率
    ├── eBPF 运行时 (Runtime)
    │   ├── kprobe/kretprobe
    │   ├── tracepoint
    │   ├── 系统调用 (syscall)
    │   └── 网络包处理 (XDP/TC)
    └── BPF 映射 (Maps)
        ├── Hash Map
        ├── Array Map
        ├── Per-CPU Map
        └── Ring Buffer

9.1.2 eBPF hook 点

Hook 类型 触发时机 典型用途
kprobe 函数入口 追踪内核函数调用、参数检查
kretprobe 函数返回 追踪返回值、性能分析
tracepoint 内核事件 系统调用追踪、调度事件
syscall 系统调用 安全监控、行为分析
XDP 网卡驱动层 高性能包过滤、DDoS 防护
TC 网络栈层 流量控制、QoS
cgroup 控制组事件 资源限制、容器监控
perf_event 性能事件 性能采样、热点分析

9.2 核心数据结构

9.2.1 eBPF 程序结构 (代码出处: include/linux/bpf.h)

// 代码出处: include/linux/bpf.h
​
/**
 * @struct bpf_prog
 * @brief eBPF 程序结构。
 */
struct bpf_prog {
    struct bpf_prog_aux *aux;               /**< 辅助数据 */
    struct bpf_insn *insnsi;                /**< 指令数组 */
    u32 len;                                /**< 指令数量 */
    u32 jited_len;                          /**< JIT 后的长度 */
    u8 *jited;                              /**< JIT 后的指令 */
    struct bpf_prog_stats *stats;           /**< 性能统计 */
    unsigned int pages;                     /**< 占用页面数 */
    struct rcu_head rcu;                    /**< RCU 头 */
    struct work_struct work;                /**< 工作队列 */
};
​
/**
 * @struct bpf_map
 * @brief eBPF 映射结构。
 */
struct bpf_map {
    const struct bpf_map_ops *ops;          /**< 映射操作 */
    void *key_size;                         /**< 键大小 */
    void *value_size;                       /**< 值大小 */
    u32 max_entries;                        /**< 最大条目数 */
    u32 map_type;                           /**< 映射类型 */
    u32 flags;                              /**< 标志 */
    u64 *memory;                            /**< 内存区域 */
    struct bpf_map *inner_map;              /**< 内层映射 */
    struct list_head list;                  /**< 链表节点 */
    struct rcu_head rcu;                    /**< RCU 头 */
};
​
/**
 * @struct bpf_prog_aux
 * @brief eBPF 程序辅助结构。
 */
struct bpf_prog_aux {
    struct bpf_prog *prog;                  /**< 关联的程序 */
    struct bpf_map **used_maps;             /**< 使用的映射 */
    u32 used_map_cnt;                       /**< 映射数量 */
    u32 stack_depth;                        /**< 栈深度 */
    u32 id;                                 /**< 程序 ID */
    const struct bpf_func_proto *func_proto; /**< 函数原型 */
    struct dentry *dentry;                  /**< debugfs 条目 */
    struct work_struct work;                /**< 工作队列 */
    struct rcu_head rcu;                    /**< RCU 头 */
};

9.3 核心代码实现

9.3.1 kprobe 挂载示例 (代码出处: samples/bpf/kprobe_example.c)

// 代码出处: samples/bpf/kprobe_example.c
​
/**
 * @brief eBPF kprobe 程序:追踪 open 系统调用。
 */
SEC("kprobe/sys_open")
int bpf_kprobe_open(struct pt_regs *ctx)
{
    // 1. 获取进程 ID 和用户 ID
    u32 pid = bpf_get_current_pid_tgid() >> 32;
    u32 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
    u64 key = pid;
    u64 *value;
​
    // 2. 获取文件名 (从寄存器中读取)
    char filename[256];
    bpf_probe_read_user_str(filename, sizeof(filename),
                           (void *)PT_REGS_PARM1(ctx));
​
    // 3. 输出追踪信息
    bpf_trace_printk("open: pid=%d uid=%d file=%s\n", pid, uid, filename);
​
    // 4. 更新统计信息
    value = bpf_map_lookup_elem(&open_stats_map, &key);
    if (!value) {
        u64 init_val = 1;
        bpf_map_update_elem(&open_stats_map, &key, &init_val, BPF_ANY);
        return 0;
    }
    (*value)++;
    bpf_map_update_elem(&open_stats_map, &key, value, BPF_ANY);
​
    return 0;
}
​
// 定义 BPF 映射
struct bpf_map_def SEC("maps") open_stats_map = {
    .type = BPF_MAP_TYPE_HASH,
    .key_size = sizeof(u64),
    .value_size = sizeof(u64),
    .max_entries = 1024,
};
​
char _license[] SEC("license") = "GPL";

9.3.2 tracepoint 挂载示例 (代码出处: samples/bpf/tracepoint_example.c)

// 代码出处: samples/bpf/tracepoint_example.c
​
/**
 * @brief eBPF tracepoint 程序:追踪系统调用。
 */
SEC("tracepoint/syscalls/sys_enter_openat")
int bpf_tracepoint_sys_enter_openat(struct trace_event_raw_sys_enter *ctx)
{
    u32 pid = bpf_get_current_pid_tgid() >> 32;
    char filename[256];
    int ret;
​
    // 1. 获取文件名参数
    ret = bpf_probe_read_user_str(filename, sizeof(filename),
                                  (void *)ctx->args[1]);
    if (ret < 0) {
        return -EIO;
    }
​
    // 2. 输出追踪信息
    bpf_trace_printk("openat: pid=%d file=%s\n", pid, filename);
​
    return 0;
}
​
char _license[] SEC("license") = "GPL";

9.3.3 加载 eBPF 程序 (用户空间) (代码出处: samples/bpf/trace_event_user.c)

// 代码出处: samples/bpf/trace_event_user.c
​
/**
 * @brief 加载并运行 BPF 程序。
 * @param obj_path BPF 目标文件路径
 * @return 0 成功,负数错误
 */
int bpf_load_program(const char *obj_path)
{
    struct bpf_object *obj;
    struct bpf_program *prog;
    struct bpf_map *map;
    int prog_fd, map_fd, ret;
​
    // 1. 打开 BPF 目标文件
    obj = bpf_object__open_file(obj_path, NULL);
    if (IS_ERR(obj)) {
        return PTR_ERR(obj);
    }
​
    // 2. 加载 BPF 程序
    ret = bpf_object__load(obj);
    if (ret < 0) {
        bpf_object__close(obj);
        return ret;
    }
​
    // 3. 获取程序文件描述符
    prog = bpf_object__find_program_by_name(obj, "bpf_kprobe_open");
    if (!prog) {
        ret = -ENOENT;
        goto out;
    }
    prog_fd = bpf_program__fd(prog);
​
    // 4. 获取映射文件描述符
    map = bpf_object__find_map_by_name(obj, "open_stats_map");
    if (!map) {
        ret = -ENOENT;
        goto out;
    }
    map_fd = bpf_map__fd(map);
​
    // 5. 挂载 kprobe
    ret = bpf_prog_attach(prog_fd, get_kprobe_events(), 0);
    if (ret < 0) {
        goto out;
    }
​
    // 6. 读取统计信息
    u64 key, value;
    for (int i = 0; i < 10; i++) {
        key = i;
        if (bpf_map_lookup_elem(map_fd, &key, &value) == 0) {
            printf("open: pid=%lld count=%lld\n", key, value);
        }
    }
​
out:
    bpf_object__close(obj);
    return ret;
}

9.3.4 使用 ring buffer 传递数据 (代码出处: samples/bpf/ring_buffer_example.c)

// 代码出处: samples/bpf/ring_buffer_example.c
​
/**
 * @brief eBPF ring buffer 程序。
 */
struct data_event {
    u32 pid;
    u32 uid;
    char comm[16];
    char filename[256];
};
​
SEC("kprobe/sys_open")
int bpf_ring_buffer_open(struct pt_regs *ctx)
{
    struct data_event *event;
    u32 pid = bpf_get_current_pid_tgid() >> 32;
    u32 uid = bpf_get_current_uid_gid() & 0xFFFFFFFF;
​
    // 1. 从 ring buffer 中申请内存
    event = bpf_ringbuf_reserve(&ring_buffer_map, sizeof(*event), 0);
    if (!event) {
        return -ENOMEM;
    }
​
    // 2. 填充事件数据
    event->pid = pid;
    event->uid = uid;
    bpf_probe_read_str(event->comm, sizeof(event->comm), current->comm);
    bpf_probe_read_user_str(event->filename, sizeof(event->filename),
                           (void *)PT_REGS_PARM1(ctx));
​
    // 3. 提交事件到 ring buffer
    bpf_ringbuf_submit(event, 0);
​
    return 0;
}
​
struct bpf_map_def SEC("maps") ring_buffer_map = {
    .type = BPF_MAP_TYPE_RINGBUF,
    .max_entries = 256 * 1024,  // 256 KB
};
​
char _license[] SEC("license") = "GPL";

9.3.5 用户空间读取 ring buffer 数据

// 代码出处: samples/bpf/ring_buffer_user.c
​
/**
 * @brief ring buffer 事件处理回调。
 * @param ctx 上下文
 * @param data 事件数据
 * @param size 事件大小
 * @return 0 成功,负数错误
 */
static int ring_buffer_event_handler(void *ctx, void *data, size_t size)
{
    struct data_event *event = (struct data_event *)data;
​
    // 1. 处理事件
    printf("open: pid=%d uid=%d comm=%s file=%s\n",
           event->pid, event->uid, event->comm, event->filename);
​
    return 0;
}
​
/**
 * @brief 读取 ring buffer 数据。
 * @param map_fd ring buffer 映射文件描述符
 * @return 0 成功,负数错误
 */
int bpf_ring_buffer_read(int map_fd)
{
    struct ring_buffer *rb;
    int ret;
​
    // 1. 创建 ring buffer 管理器
    rb = ring_buffer__new(map_fd, ring_buffer_event_handler, NULL);
    if (!rb) {
        return -ENOMEM;
    }
​
    // 2. 轮询 ring buffer
    while (1) {
        ret = ring_buffer__poll(rb, 100);
        if (ret < 0) {
            break;
        }
    }
​
    // 3. 清理
    ring_buffer__free(rb);
​
    return ret;
}

9.3.6 BPF Map 操作

// 代码出处: kernel/bpf/map.c
​
/**
 * @brief 创建 BPF 映射。
 * @param map_type 映射类型
 * @param key_size 键大小
 * @param value_size 值大小
 * @param max_entries 最大条目数
 * @param flags 标志
 * @return 映射文件描述符,负数错误
 */
int bpf_map_create(enum bpf_map_type map_type, u32 key_size,
                    u32 value_size, u32 max_entries, u32 flags)
{
    struct bpf_map *map;
    int ret;
​
    // 1. 检查权限
    if (!capable(CAP_BPF)) {
        return -EPERM;
    }
​
    // 2. 分配映射结构
    map = kmalloc(sizeof(*map), GFP_KERNEL);
    if (!map) {
        return -ENOMEM;
    }
​
    map->map_type = map_type;
    map->key_size = key_size;
    map->value_size = value_size;
    map->max_entries = max_entries;
    map->flags = flags;
    INIT_LIST_HEAD(&map->list);
    map->ops = bpf_map_ops;
​
    // 3. 分配内存
    map->memory = kmalloc(max_entries * value_size, GFP_KERNEL);
    if (!map->memory) {
        kfree(map);
        return -ENOMEM;
    }
​
    // 4. 注册映射
    ret = bpf_map_register(map);
    if (ret < 0) {
        kfree(map->memory);
        kfree(map);
        return ret;
    }
​
    // 5. 返回文件描述符
    return bpf_map_get_fd(map);
}
​
/**
 * @brief 从 BPF 映射中查找条目。
 * @param map_fd 映射文件描述符
 * @param key 键指针
 * @param value 值指针
 * @return 0 成功,负数错误
 */
int bpf_map_lookup_elem(int map_fd, void *key, void *value)
{
    struct bpf_map *map = bpf_map_fd_get(map_fd);
    u32 key_offset = (u32)key - (u32)map->memory;
    u32 value_offset = (u32)value - (u32)map->memory;
​
    // 1. 检查偏移量
    if (key_offset >= map->max_entries * map->key_size) {
        return -EINVAL;
    }
    if (value_offset >= map->max_entries * map->value_size) {
        return -EINVAL;
    }
​
    // 2. 复制值
    memcpy(value, map->memory + value_offset, map->value_size);
​
    return 0;
}

9.4 软件设计模式树形分析

eBPF 编程设计模式
├── 工厂模式 (Factory Pattern)
│   ├── bpf_object__open_file():创建 BPF 对象
│   └── bpf_map_create():创建 BPF 映射
├── 适配器模式 (Adapter Pattern)
│   ├── bpf_prog_attach():适配 BPF 程序到 kprobe
│   └── ring_buffer__new():适配 ring buffer 到用户空间
├── 策略模式 (Strategy Pattern)
│   ├── bpf_kprobe_open():kprobe 追踪策略
│   └── bpf_tracepoint_sys_enter_openat():tracepoint 追踪策略
├── 观察者模式 (Observer Pattern)
│   ├── bpf_ring_buffer_read():观察 ring buffer 事件
│   └── ring_buffer_event_handler():观察事件回调
├── 状态模式 (State Pattern)
│   └── BPF 程序状态 (LOADED/ATTACHED/RUNNING/UNLOADED)
└── 模板方法模式 (Template Method Pattern)
    └── bpf_load_program():定义了 BPF 程序加载的标准流程

9.5 eBPF 调试核心难点

9.5.1 验证器错误

现象:加载 BPF 程序时返回 -EINVAL,验证器报告 "invalid bpf program"。

原因

  1. BPF 程序循环次数超出限制。

  2. BPF 栈大小超过 512 字节。

  3. BPF 映射访问越界。

调试方法

  1. 使用 bpftool prog dump xlated 查看指令。

  2. 检查程序是否包含循环。

  3. 减少栈使用或使用映射。

9.5.2 kprobe 挂载失败

现象bpf_prog_attach 返回 -ENOENT,无法挂载 kprobe。

原因

  1. 函数名错误或函数不存在。

  2. 内核未启用 CONFIG_KPROBE。

  3. 权限不足。

调试方法

  1. 检查函数是否存在:cat /proc/kallsyms | grep do_sys_open

  2. 检查内核配置:zgrep CONFIG_KPROBE /proc/config.gz

  3. 使用 sudo 执行。

9.5.3 Ring buffer 溢出

现象bpf_ringbuf_reserve 返回 NULL,ring buffer 溢出。

原因

  1. ring buffer 太小。

  2. 事件产生速度过快。

  3. 用户空间处理速度慢。

调试方法

  1. 增加 ring buffer 大小。

  2. 在 BPF 程序中增加丢包策略。

  3. 使用 bpftool map dump 查看 ring buffer 状态。

9.6 与其他模块的协同

模块 协同方式 调试关键点
kprobe 挂载 BPF 程序到函数入口 函数参数、返回值
tracepoint 挂载 BPF 程序到内核事件 事件数据、上下文
perf_event 挂载 BPF 程序到性能事件 性能采样、热点分析
XDP 挂载 BPF 程序到网卡驱动层 包处理、过滤策略
TC 挂载 BPF 程序到网络栈层 流量控制、QoS
cgroup 挂载 BPF 程序到控制组 资源限制、容器监控

第十部分 Android 内核特性分析与优化

10.1 Android 内核特性概述

Android 内核基于 Linux 主线内核,但包含大量 Android 特有的增强和优化。这些特性包括 Binder IPC 优化、Low Memory Killer (LMK) 增强、Ashmem 共享内存、ION 内存分配器、F2FS 文件系统优化、SELinux 策略等。理解这些特性并进行针对性优化,是提升 Android 系统性能和稳定性的关键。

10.1.1 Android 内核特性全景

[Android 内核特性]
    ├── [IPC 优化]
    │   ├── Binder 优化 (oneway 事务、线程池管理)
    │   ├── Ashmem 共享内存 (优化 TLB 刷新)
    │   └── ION 内存分配器 (连续内存分配、DMA-BUF)
    ├── [内存优化]
    │   ├── Low Memory Killer (进程优先级、杀进程策略)
    │   ├── ZRAM 压缩 (压缩算法选择、交换策略)
    │   └── KSM (Kernel Samepage Merging)
    ├── [文件系统优化]
    │   ├── F2FS (Flash-Friendly File System)
    │   ├── EROFS (Enhanced Read-Only File System)
    │   └── FUSE 优化
    ├── [电源优化]
    │   ├── Suspend/Resume 优化
    │   ├── 唤醒源管理
    │   └── CPU 热插拔
    └── [安全优化]
        ├── SELinux 策略优化
        ├── TrustZone 集成
        └── 安全启动 (dm-verity)

10.1.2 Android 内核优化目标

优化目标 核心指标 优化手段
响应速度 应用启动时间、触控响应 Binder 优先队列、LMK 策略
内存效率 内存占用、进程生命周期 ZRAM 压缩、KSM、ION 池
存储性能 读写速度、I/O 延迟 F2FS 优化、EROFS 压缩
电源效率 待机功耗、唤醒次数 Suspend/Resume 优化、唤醒源管理
安全性 安全漏洞数量 SELinux 策略、内核加固
稳定性 崩溃次数、内核 panic 内存腐蚀检测、死锁检测

10.2 核心优化实现

10.2.1 Binder 优化 (代码出处: drivers/android/binder.c)

// 代码出处: drivers/android/binder.c
​
/**
 * @brief Binder 事务池优化:预分配事务池。
 * @param proc Binder 进程指针
 * @param pool_size 池大小
 * @return 0 成功,负数错误
 */
int binder_prealloc_transaction_pool(struct binder_proc *proc, int pool_size)
{
    struct binder_transaction *t;
    int i;
​
    // 1. 预分配事务池
    proc->transaction_pool = kcalloc(pool_size, sizeof(*t), GFP_KERNEL);
    if (!proc->transaction_pool) {
        return -ENOMEM;
    }
​
    // 2. 初始化事务池
    for (i = 0; i < pool_size; i++) {
        t = &proc->transaction_pool[i];
        t->from_proc = proc;
        t->to_proc = proc;
        t->buffer = binder_alloc_new(&proc->alloc, 1024);
        INIT_LIST_HEAD(&t->list);
    }
​
    return 0;
}
​
/**
 * @brief Binder 线程池优化:动态调整线程数量。
 * @param proc Binder 进程指针
 * @param delta 变化量
 * @return 0 成功,负数错误
 */
int binder_adjust_thread_pool(struct binder_proc *proc, int delta)
{
    int target = proc->thread_count + delta;
​
    // 1. 检查线程数量范围
    if (target < proc->min_threads) {
        target = proc->min_threads;
    }
    if (target > proc->max_threads) {
        target = proc->max_threads;
    }
​
    // 2. 调整线程数量
    while (proc->thread_count < target) {
        int tid = binder_create_thread(proc);
        if (tid < 0) {
            return tid;
        }
        proc->thread_count++;
    }
​
    while (proc->thread_count > target) {
        binder_stop_thread(proc);
        proc->thread_count--;
    }
​
    return 0;
}
​
/**
 * @brief Binder oneway 事务优化:批量处理。
 * @param proc Binder 进程指针
 * @param t 事务指针
 * @return 0 成功,负数错误
 */
int binder_oneway_batch(struct binder_proc *proc, struct binder_transaction *t)
{
    struct binder_transaction *next;
​
    // 1. 检查是否支持批量处理
    if (!t->flags & BINDER_TRANSACTION_FLAG_ONEWAY) {
        return -EINVAL;
    }
​
    // 2. 批量处理事务
    list_for_each_entry(next, &proc->oneway_queue, list) {
        if (next->to_proc == t->to_proc) {
            // 合并事务
            binder_transaction_merge(t, next);
            return 0;
        }
    }
​
    // 3. 添加到队列
    list_add_tail(&t->list, &proc->oneway_queue);
​
    return 0;
}

10.2.2 Low Memory Killer 优化 (代码出处: drivers/staging/android/lowmemorykiller.c)

// 代码出处: drivers/staging/android/lowmemorykiller.c
​
/**
 * @brief LMK 杀进程策略优化:优先杀后台进程。
 * @param task 任务指针
 * @return 0 不杀,>0 杀
 */
int lowmem_kill_priority(struct task_struct *task)
{
    int oom_score_adj = task->signal->oom_score_adj;
    int priority = task->prio;
    int flags = task->flags;
​
    // 1. 检查是否为前台进程
    if (oom_score_adj < OOM_SCORE_ADJ_FOREGROUND) {
        return 0;  // 前台进程不杀
    }
​
    // 2. 检查是否为系统服务
    if (flags & PF_SYSTEM) {
        return 0;  // 系统服务不杀
    }
​
    // 3. 检查是否为内核线程
    if (flags & PF_KTHREAD) {
        return 0;  // 内核线程不杀
    }
​
    // 4. 根据优先级计算杀进程分数
    int score = oom_score_adj * 100 / OOM_SCORE_ADJ_MAX;
    if (priority > 100) {
        score += 50;  // 高优先级进程加分
    }
    if (flags & PF_IO_WORKER) {
        score += 30;  // I/O 工作进程加分
    }
​
    return score;
}
​
/**
 * @brief LMK 杀进程策略优化:批量杀进程。
 * @param minfree 最小空闲页面数
 * @param kill_count 杀进程数量
 * @return 释放的页面数
 */
int lowmem_batch_kill(unsigned long minfree, int kill_count)
{
    struct task_struct *task;
    struct mm_struct *mm;
    unsigned long freed = 0;
    int killed = 0;
​
    // 1. 扫描所有进程
    rcu_read_lock();
    for_each_process(task) {
        if (killed >= kill_count) {
            break;
        }
​
        mm = task->mm;
        if (!mm) {
            continue;
        }
​
        // 2. 计算杀进程分数
        int score = lowmem_kill_priority(task);
        if (score <= 0) {
            continue;
        }
​
        // 3. 发送 SIGKILL
        send_sig(SIGKILL, task, 0);
        killed++;
        freed += get_mm_rss(mm);
​
        // 4. 记录日志
        pr_info("LMK: batch kill pid=%d comm=%s score=%d\n",
                task->pid, task->comm, score);
    }
    rcu_read_unlock();
​
    return freed;
}

10.2.3 ZRAM 压缩优化 (代码出处: drivers/block/zram/zram_drv.c)

// 代码出处: drivers/block/zram/zram_drv.c
​
/**
 * @brief ZRAM 压缩算法选择优化。
 * @param zram ZRAM 设备指针
 * @param algo 算法名称
 * @return 0 成功,负数错误
 */
int zram_select_best_algorithm(struct zram *zram, const char *algo)
{
    struct zram_compressor *comp;
    size_t max_size = 0;
    const char *best_algo = NULL;
​
    // 1. 计算最佳压缩算法
    if (strcmp(algo, "lz4") == 0) {
        // LZ4 速度快,但压缩率低
        comp = zram_get_compressor(zram, "lz4");
        if (comp->compress(zram->comp, "test", "test", 4, &max_size) == 0) {
            best_algo = "lz4";
        }
    } else if (strcmp(algo, "lz4hc") == 0) {
        // LZ4HC 压缩率高,但速度慢
        comp = zram_get_compressor(zram, "lz4hc");
        if (comp->compress(zram->comp, "test", "test", 4, &max_size) == 0) {
            best_algo = "lz4hc";
        }
    } else if (strcmp(algo, "zstd") == 0) {
        // ZSTD 压缩率高,速度中等
        comp = zram_get_compressor(zram, "zstd");
        if (comp->compress(zram->comp, "test", "test", 4, &max_size) == 0) {
            best_algo = "zstd";
        }
    }
​
    // 2. 设置最佳算法
    if (best_algo) {
        zram_set_algo(zram, best_algo);
        return 0;
    }
​
    // 3. 默认使用 LZO
    zram_set_algo(zram, "lzo");
    return 0;
}
​
/**
 * @brief ZRAM 自适应压缩策略。
 * @param zram ZRAM 设备指针
 * @param size 压缩大小
 * @return 压缩策略
 */
int zram_adaptive_compression(struct zram *zram, size_t size)
{
    // 1. 根据大小选择压缩策略
    if (size < 256) {
        // 小数据块,使用 LZ4 快速压缩
        zram_set_algo(zram, "lz4");
        return 0;
    } else if (size < 4096) {
        // 中等数据块,使用 ZSTD
        zram_set_algo(zram, "zstd");
        return 0;
    } else {
        // 大数据块,使用 LZ4HC 高压缩
        zram_set_algo(zram, "lz4hc");
        return 0;
    }
}

10.2.4 F2FS 文件系统优化 (代码出处: fs/f2fs/)

// 代码出处: fs/f2fs/sysfs.c
​
/**
 * @brief F2FS 自适应 I/O 调度。
 * @param sb 超级块指针
 * @param readahead 预读大小
 * @param sync 是否同步
 * @return 0 成功,负数错误
 */
int f2fs_adaptive_io_schedule(struct super_block *sb, size_t readahead, int sync)
{
    struct f2fs_sb_info *sbi = F2FS_SB(sb);
    int ret = 0;
​
    // 1. 检查 I/O 负载
    if (sbi->io_load > 50) {
        // 高负载时,减少预读
        readahead = readahead / 2;
        if (readahead < 32) {
            readahead = 32;
        }
    }
​
    // 2. 根据同步/异步调整 I/O 策略
    if (sync) {
        // 同步 I/O 优先级高
        sbi->io_priority = 100;
        ret = f2fs_submit_io(sbi, F2FS_WRITE, readahead, sync);
    } else {
        // 异步 I/O 优先级低
        sbi->io_priority = 50;
        ret = f2fs_submit_io(sbi, F2FS_READ, readahead, sync);
    }
​
    return ret;
}
​
/**
 * @brief F2FS 垃圾回收优化。
 * @param sb 超级块指针
 * @return 0 成功,负数错误
 */
int f2fs_optimize_gc(struct super_block *sb)
{
    struct f2fs_sb_info *sbi = F2FS_SB(sb);
​
    // 1. 检查空闲空间
    if (sbi->free_segments < 10) {
        // 空闲空间不足,启动紧急 GC
        return f2fs_urgent_gc(sbi);
    }
​
    // 2. 检查 GC 触发阈值
    if (sbi->need_gc > 100) {
        // 触发 GC
        return f2fs_trigger_gc(sbi);
    }
​
    // 3. 定期 GC
    if (sbi->gc_interval > 1000) {
        // 启动定期 GC
        return f2fs_periodic_gc(sbi);
    }
​
    return 0;
}

10.2.5 唤醒源管理优化 (代码出处: drivers/base/power/wakeup.c)

// 代码出处: drivers/base/power/wakeup.c
​
/**
 * @brief 唤醒源聚合优化。
 * @param ws 唤醒源指针
 * @return 0 成功,负数错误
 */
int wakeup_source_aggregate(struct wakeup_source *ws)
{
    struct wakeup_source *tmp;
    unsigned long last_wakeup = 0;
​
    // 1. 查找相近的唤醒源
    list_for_each_entry(tmp, &wakeup_source_list, list) {
        if (tmp == ws) {
            continue;
        }
        if (abs(tmp->last_wakeup_time - ws->last_wakeup_time) < 1000) {
            // 时间相近,合并
            last_wakeup = max(tmp->last_wakeup_time, ws->last_wakeup_time);
            ws->last_wakeup_time = last_wakeup;
            ws->wakeup_count += tmp->wakeup_count;
            // 删除重复的唤醒源
            list_del(&tmp->list);
            kfree(tmp);
        }
    }
​
    return 0;
}
​
/**
 * @brief 唤醒源优先级优化。
 * @param ws 唤醒源指针
 * @return 优先级值
 */
int wakeup_source_priority(struct wakeup_source *ws)
{
    int priority = 0;
​
    // 1. 根据唤醒源类型计算优先级
    if (strcmp(ws->name, "power_button") == 0) {
        priority = 100;  // 电源键最高优先级
    } else if (strcmp(ws->name, "touchscreen") == 0) {
        priority = 90;   // 触摸屏高优先级
    } else if (strcmp(ws->name, "rtc") == 0) {
        priority = 50;   // RTC 中等优先级
    } else if (strcmp(ws->name, "usb") == 0) {
        priority = 30;   // USB 低优先级
    } else {
        priority = 10;   // 其他唤醒源
    }
​
    // 2. 根据唤醒次数调整优先级
    if (ws->wakeup_count > 100) {
        priority += 20;
    }
​
    return priority;
}

10.3 软件设计模式树形分析

Android 内核优化设计模式
├── 工厂模式 (Factory Pattern)
│   ├── binder_prealloc_transaction_pool():预分配事务池
│   └── zram_select_best_algorithm():创建压缩算法实例
├── 适配器模式 (Adapter Pattern)
│   ├── lowmem_batch_kill():适配杀进程策略
│   └── wakeup_source_aggregate():适配唤醒源管理
├── 策略模式 (Strategy Pattern)
│   ├── lowmem_kill_priority():杀进程优先级策略
│   ├── zram_adaptive_compression():自适应压缩策略
│   └── f2fs_adaptive_io_schedule():自适应 I/O 调度策略
├── 观察者模式 (Observer Pattern)
│   ├── f2fs_optimize_gc():观察 GC 触发条件
│   └── wakeup_source_priority():观察唤醒优先级
└── 模板方法模式 (Template Method Pattern)
    └── binder_adjust_thread_pool():定义了线程池调整的标准流程

10.4 Android 内核优化调试核心难点

10.4.1 Binder 事务队列阻塞

现象:Binder 事务队列过长,系统响应缓慢。

原因

  1. 事务池太小。

  2. 线程池不足。

  3. oneway 事务过多。

调试方法

  1. 使用 dumpsys binder 查看事务队列状态。

  2. 调整 binder_prealloc_transaction_pool 池大小。

  3. 优化 oneway 事务批处理。

10.4.2 LMK 杀进程不当

现象:LMK 杀死重要进程,导致系统不稳定。

原因

  1. oom_score_adj 配置错误。

  2. 杀进程策略过于激进。

  3. 进程优先级未正确设置。

调试方法

  1. 检查 /proc/pid/oom_score_adj 查看进程优先级。

  2. 调整 lowmem_kill_priority 评分策略。

  3. 增加杀进程延迟。

10.4.3 ZRAM 压缩率过低

现象:ZRAM 压缩率低,内存利用率不足。

原因

  1. 压缩算法选择不当。

  2. 数据块大小不匹配。

  3. 压缩策略配置错误。

调试方法

  1. 使用 cat /sys/block/zram0/comp_algorithm 查看压缩算法。

  2. 调整 zram_adaptive_compression 策略。

  3. 增加 ZRAM 大小。

10.5 与其他模块的协同

模块 协同方式 调试关键点
Binder 提供 IPC 优化 事务池大小、线程池管理
LMK 提供内存回收优化 杀进程策略、进程优先级
ZRAM 提供压缩优化 算法选择、压缩策略
F2FS 提供文件系统优化 I/O 调度、GC 策略
唤醒源管理 提供电源优化 唤醒聚合、优先级管理
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐