当前位置: 首页 > news >正文

【Android】 android suspend/resume总结(3)

一、摘要

本文深入分析了Linux内核中设备电源管理的核心实现文件drivers/base/power/main.c,详细阐述了系统级挂起(suspend)和恢复(resume)的完整流程。通过对源码的深入剖析,揭示了Linux内核如何通过分阶段处理、设备依赖管理、异步优化等机制来实现高效可靠的设备电源管理。

二、概述

这个文件是 Linux 设备模型中电源管理的核心实现,负责管理系统中所有设备的挂起(suspend)和恢复(resume)操作。

1、核心数据结构

LIST_HEAD(dpm_list);                    // 主设备列表
static LIST_HEAD(dpm_prepared_list);    // 已准备的设备列表
static LIST_HEAD(dpm_suspended_list);   // 已挂起的设备列表
static LIST_HEAD(dpm_late_early_list);  // 晚期/早期处理列表
static LIST_HEAD(dpm_noirq_list);       // 无中断处理列表

2、Suspend 流程详细分析

graph TDA[dpm_suspend_start] --> B[dpm_prepare]B --> C[dpm_suspend]A --> D[dpm_suspend_end]D --> E[dpm_suspend_late]E --> F[dpm_suspend_noirq]B --> B1[device_prepare]C --> C1[device_suspend]E --> E1[device_suspend_late]F --> F1[device_suspend_noirq]B1 --> B2[移动到dpm_prepared_list]C1 --> C2[移动到dpm_suspended_list]E1 --> E2[移动到dpm_late_early_list]F1 --> F2[移动到dpm_noirq_list]
正常运行 → 准备阶段 → 挂起阶段 → 晚期挂起 → 无中断挂起↓         ↑         ↑         ↑         ↑
完成阶段 ← 恢复阶段 ← 早期恢复 ← 无中断恢复 ← [最深睡眠]

1、详细函数分析

int dpm_suspend_start(pm_message_t state)
{ktime_t starttime = ktime_get();int error;error = dpm_prepare(state);if (error)dpm_save_failed_step(SUSPEND_PREPARE);elseerror = dpm_suspend(state);dpm_show_time(starttime, state, error, "start");return error;
}
功能: 启动设备挂起流程的入口函数调用 dpm_prepare() 准备所有设备调用 dpm_suspend() 挂起所有设备记录执行时间和错误信息
int dpm_prepare(pm_message_t state)
{int error = 0;wait_for_device_probe();        // 等待设备探测完成device_block_probing();         // 阻止新设备探测mutex_lock(&dpm_list_mtx);while (!list_empty(&dpm_list) && !error) {struct device *dev = to_device(dpm_list.next);get_device(dev);mutex_unlock(&dpm_list_mtx);error = device_prepare(dev, state);mutex_lock(&dpm_list_mtx);if (!error) {dev->power.is_prepared = true;list_move_tail(&dev->power.entry, &dpm_prepared_list);}put_device(dev);}mutex_unlock(&dpm_list_mtx);return error;
}
功能: 准备阶段阻止新设备的探测和注册遍历 dpm_list 中的所有设备调用每个设备的 prepare 回调将准备好的设备移动到 dpm_prepared_list
static int device_prepare(struct device *dev, pm_message_t state)
{int (*callback)(struct device *) = NULL;int ret = 0;pm_runtime_get_noresume(dev);   // 阻止运行时挂起if (dev->power.syscore)return 0;device_lock(dev);// 按优先级选择回调函数if (dev->pm_domain)callback = dev->pm_domain->ops.prepare;else if (dev->type && dev->type->pm)callback = dev->type->pm->prepare;else if (dev->class && dev->class->pm)callback = dev->class->pm->prepare;else if (dev->bus && dev->bus->pm)callback = dev->bus->pm->prepare;if (!callback && dev->driver && dev->driver->pm)callback = dev->driver->pm->prepare;if (callback)ret = callback(dev);device_unlock(dev);// 设置直接完成标志spin_lock_irq(&dev->power.lock);dev->power.direct_complete = state.event == PM_EVENT_SUSPEND &&(ret > 0 || dev->power.no_pm_callbacks) &&!dev_pm_test_driver_flags(dev, DPM_FLAG_NO_DIRECT_COMPLETE);spin_unlock_irq(&dev->power.lock);return 0;
}
功能: 单个设备的准备选择合适的 prepare 回调函数(优先级:pm_domain > type(设备模型中的一个抽象层,主要用于将设备归类) > class(用于表示设备所属的“设备类”) > bus > driver)执行回调函数设置 direct_complete 标志用于优化
int dpm_suspend(pm_message_t state)
{ktime_t starttime = ktime_get();int error = 0;devfreq_suspend();      // 挂起设备频率调节cpufreq_suspend();      // 挂起CPU频率调节pm_transition = state;async_error = 0;mutex_lock(&dpm_list_mtx);while (!list_empty(&dpm_prepared_list)) {struct device *dev = to_device(dpm_prepared_list.prev);list_move(&dev->power.entry, &dpm_suspended_list);if (dpm_async_fn(dev, async_suspend))continue;get_device(dev);mutex_unlock(&dpm_list_mtx);error = device_suspend(dev, state, false);put_device(dev);mutex_lock(&dpm_list_mtx);if (error || async_error)break;}mutex_unlock(&dpm_list_mtx);async_synchronize_full();return error;
}
功能: 主要挂起阶段挂起 CPU 和设备频率调节支持异步挂起以提高性能将设备从 dpm_prepared_list 移动到 dpm_suspended_list
static int dpm_noirq_suspend_devices(pm_message_t state)
{/* 记录函数开始执行的时间,用于性能统计 */ktime_t starttime = ktime_get();int error = 0;/* 开始追踪无中断挂起阶段,用于系统调试和性能分析 */trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true);/* 设置全局电源管理转换状态,供其他函数使用 */pm_transition = state;/* 重置异步错误标志,为新的挂起流程做准备 */async_error = 0;/* * 获取设备电源管理列表的互斥锁* 这是关键的同步机制,确保多线程环境下列表操作的原子性*/mutex_lock(&dpm_list_mtx);/** 主要处理循环:处理所有在晚期挂起列表中的设备* * 处理顺序说明:* - 从dpm_late_early_list的尾部开始处理(LIFO - 后进先出)* - 这确保了子设备在父设备之前被挂起* - 维护了正确的设备依赖关系顺序*/while (!list_empty(&dpm_late_early_list)) {/* * 获取列表中的最后一个设备(最晚进入晚期挂起的设备)* 使用LIFO顺序确保依赖关系的正确性:* 子设备先挂起,父设备后挂起*/struct device *dev = to_device(dpm_late_early_list.prev);/** 关键的列表状态转换:* 将设备从 dpm_late_early_list 移动到 dpm_noirq_list* * 状态转换意义:* dpm_late_early_list: 已完成晚期挂起,准备无中断挂起* dpm_noirq_list: 正在进行或已完成无中断挂起*/list_move(&dev->power.entry, &dpm_noirq_list);/** 尝试异步处理设备挂起* * 异步处理的优势:* 1. 提高系统挂起性能,减少总体挂起时间* 2. 允许独立设备并行处理* 3. 不影响有依赖关系的设备的正确顺序* * 如果设备支持异步处理且异步调度成功,则continue跳过同步处理*/if (dpm_async_fn(dev, async_suspend_noirq))continue;/** 同步处理路径:* 对于不支持异步处理或异步调度失败的设备*//* 增加设备引用计数,防止设备在处理过程中被意外释放 */get_device(dev);/** 临时释放互斥锁的重要原因:* 1. device_suspend_noirq可能是耗时操作* 2. 允许异步处理的设备继续执行* 3. 避免长时间持有锁导致的性能问题* 4. 防止死锁情况的发生*/mutex_unlock(&dpm_list_mtx);/** 执行设备的无中断挂起操作* * 这是核心的设备挂起逻辑:* - 调用设备特定的suspend_noirq回调函数* - 在中断被禁用的环境中执行* - 处理设备的最终挂起状态设置* - async参数为false表示这是同步处理*/error = device_suspend_noirq(dev, state, false);/* 减少设备引用计数,与前面的get_device配对 */put_device(dev);/* 重新获取互斥锁,准备处理下一个设备或检查错误 */mutex_lock(&dpm_list_mtx);/** 错误检查和处理:* * 检查两种类型的错误:* 1. error: 当前设备同步处理的错误* 2. async_error: 异步处理设备产生的错误* * 任何错误都会导致整个挂起流程中断,这是为了:* - 保证系统状态的一致性* - 避免部分设备挂起导致的不稳定状态* - 及时发现和处理硬件或驱动问题*/if (error || async_error)break;}/* 释放设备电源管理列表互斥锁 */mutex_unlock(&dpm_list_mtx);/** 等待所有异步操作完成* * 这个调用的重要性:* 1. 确保所有异步启动的设备挂起操作都已完成* 2. 收集异步操作中可能产生的错误* 3. 保证函数返回时所有设备都已处理完毕* 4. 维护系统状态的一致性*/async_synchronize_full();/** 最终错误状态确定:* 如果同步处理没有错误,但异步处理有错误,* 则将异步错误作为最终错误返回*/if (!error)error = async_error;/** 错误记录和调试支持:* 如果挂起过程中发生错误,记录失败的步骤* 这对于系统调试和问题诊断非常重要*/if (error)dpm_save_failed_step(SUSPEND_SUSPEND_NOIRQ);/** 性能统计和监控:* 显示无中断挂起阶段的执行时间* 包括成功/失败状态,用于性能分析和优化*/dpm_show_time(starttime, state, error, "noirq");/* 结束追踪无中断挂起阶段 */trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, false);/* 返回最终的错误状态 */return error;
}
static int device_suspend(struct device *dev, pm_message_t state, bool async)
{pm_callback_t callback = NULL;const char *info = NULL;int error = 0;DECLARE_DPM_WATCHDOG_ON_STACK(wd);dpm_wait_for_subordinate(dev, async);   // 等待子设备完成pm_runtime_barrier(dev);                // 等待运行时PM完成if (pm_wakeup_pending()) {async_error = -EBUSY;goto Complete;}// 处理 direct_complete 优化if (dev->power.direct_complete) {if (pm_runtime_status_suspended(dev)) {pm_runtime_disable(dev);if (pm_runtime_status_suspended(dev)) {dev->power.is_suspended = true;goto Complete;}pm_runtime_enable(dev);}dev->power.direct_complete = false;}dpm_watchdog_set(&wd, dev);device_lock(dev);// 选择回调函数(优先级同prepare)if (dev->pm_domain) {info = "power domain ";callback = pm_op(&dev->pm_domain->ops, state);} else if (dev->type && dev->type->pm) {info = "type ";callback = pm_op(dev->type->pm, state);}// ... 其他优先级选择error = dpm_run_callback(callback, dev, state, info);if (!error) {dev->power.is_suspended = true;if (device_may_wakeup(dev))dev->power.wakeup_path = true;dmp_propagate_wakeup_to_parent(dev);}device_unlock(dev);dpm_watchdog_clear(&wd);Complete:complete_all(&dev->power.completion);return error;
}
功能: 单个设备挂起等待子设备和依赖设备完成处理 direct_complete 优化设置看门狗防止挂起超时执行设备特定的挂起回调处理唤醒路径传播

3、Resume 流程详细分析

graph TDA[dpm_resume_start] --> B[dpm_resume_noirq]B --> C[dpm_resume_early]A --> D[dpm_resume_end]D --> E[dpm_resume]E --> F[dpm_complete]B --> B1[device_resume_noirq]C --> C1[device_resume_early]E --> E1[device_resume]F --> F1[device_complete]B1 --> B2[从dpm_noirq_list移动到dmp_late_early_list]C1 --> C2[从dpm_late_early_list移动到dpm_suspended_list]E1 --> E2[从dpm_suspended_list移动到dpm_prepared_list]F1 --> F2[从dpm_prepared_list移动到dpm_list]

1、详细函数分析

void dpm_resume_start(pm_message_t state)
{dpm_resume_noirq(state);dpm_resume_early(state);
}
void dpm_resume_noirq(pm_message_t state)
{dpm_noirq_resume_devices(state);resume_device_irqs();           // 恢复设备中断device_wakeup_disarm_wake_irqs(); // 解除唤醒中断
}
static void dpm_noirq_resume_devices(pm_message_t state)
{struct device *dev;ktime_t starttime = ktime_get();/* 开始追踪无中断恢复阶段 */trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, true);/* 重置异步错误标志 */async_error = 0;/* 设置当前电源管理转换状态 */pm_transition = state;/* 获取设备电源管理列表互斥锁,确保线程安全 */mutex_lock(&dpm_list_mtx);/** 第一阶段:启动异步设备的恢复* 优先触发"异步"设备的恢复,这样它们就不必等待* 那些它们不依赖的"非异步"设备完成* 这是一个重要的性能优化策略*/list_for_each_entry(dev, &dpm_noirq_list, power.entry)dpm_async_fn(dev, async_resume_noirq);/** 第二阶段:处理同步设备和等待异步设备完成* 从dpm_noirq_list的头部开始处理设备(FIFO顺序)* 这确保了设备按照正确的依赖顺序进行恢复*/while (!list_empty(&dpm_noirq_list)) {/* 获取列表中的第一个设备(最早进入的设备) */dev = to_device(dpm_noirq_list.next);/* * 将设备从dpm_noirq_list移动到dpm_late_early_list* 这标志着设备已经完成了无中断恢复阶段,* 准备进入下一个恢复阶段(早期恢复阶段)*/list_move_tail(&dev->power.entry, &dpm_late_early_list);/** 检查设备是否正在进行异步处理* 如果设备没有在异步处理中,则进行同步处理*/if (!dev->power.async_in_progress) {/* 增加设备引用计数,防止设备在处理过程中被释放 */get_device(dev);/* * 临时释放互斥锁,允许其他线程访问设备列表* 这在执行可能耗时的设备操作时很重要*/mutex_unlock(&dpm_list_mtx);/* * 执行设备的无中断恢复操作* 这是核心的设备恢复逻辑,会调用设备特定的resume_noirq回调* async参数为false表示这是同步处理*/device_resume_noirq(dev, state, false);/* 减少设备引用计数 */put_device(dev);/* 重新获取互斥锁,继续处理下一个设备 */mutex_lock(&dpm_list_mtx);}/** 如果设备正在异步处理中,则跳过同步处理* 异步处理会在后面的async_synchronize_full()中等待完成*/}/* 释放设备电源管理列表互斥锁 */mutex_unlock(&dpm_list_mtx);/** 等待所有异步操作完成* 这确保了所有设备(无论是同步还是异步处理的)* 都已经完成了无中断恢复阶段*/async_synchronize_full();/* * 显示无中断恢复阶段的执行时间统计* 这对于性能分析和调试很有用*/dpm_show_time(starttime, state, 0, "noirq");/** 检查是否有异步错误发生* 如果有错误,保存失败步骤信息用于调试*/if (async_error)dpm_save_failed_step(SUSPEND_RESUME_NOIRQ);/* 结束追踪无中断恢复阶段 */trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false);
}
static void device_resume_noirq(struct device *dev, pm_message_t state, bool async)
{pm_callback_t callback = NULL;const char *info = NULL;bool skip_resume;int error = 0;if (!dev->power.is_noirq_suspended)goto Out;if (!dpm_wait_for_superior(dev, async))goto Out;skip_resume = dev_pm_skip_resume(dev);// 根据skip_resume设置运行时PM状态if (skip_resume)pm_runtime_set_suspended(dev);else if (dev_pm_skip_suspend(dev))pm_runtime_set_active(dev);// 选择回调函数if (dev->pm_domain) {info = "noirq power domain ";callback = pm_noirq_op(&dev->pm_domain->ops, state);}// ... 其他选择逻辑if (callback)goto Run;if (skip_resume)goto Skip;if (dev->driver && dev->driver->pm) {info = "noirq driver ";callback = pm_noirq_op(dev->driver->pm, state);}Run:error = dpm_run_callback(callback, dev, state, info);Skip:dev->power.is_noirq_suspended = false;Out:complete_all(&dev->power.completion);
}
static bool dpm_wait_for_superior(struct device *dev, bool async)
{struct device *parent;mutex_lock(&dpm_list_mtx);if (!device_pm_initialized(dev)) {mutex_unlock(&dpm_list_mtx);return false;}parent = get_device(dev->parent);mutex_unlock(&dpm_list_mtx);dpm_wait(parent, async);            // 等待父设备put_device(parent);dpm_wait_for_suppliers(dev, async); // 等待供应商设备return device_pm_initialized(dev);
}
    A[设备回调选择] --> B{pm_domain存在?}B -->|| C[使用pm_domain回调]B -->|| D{type存在?}D -->|| E[使用type回调]D -->|| F{class存在?}F -->|| G[使用class回调]F -->|| H{bus存在?}H -->|| I[使用bus回调]H -->|| J[使用driver回调]

总结

/* 列表状态转换 */
dpm_list → dpm_prepared_list     (prepare完成)
dpm_prepared_list → dpm_suspended_list   (suspend完成)
dmp_suspended_list → dpm_late_early_list (suspend_late完成)
dpm_late_early_list → dpm_noirq_list     (suspend_noirq完成)dpm_noirq_list → dpm_late_early_list     (resume_noirq完成)
dpm_late_early_list → dpm_suspended_list (resume_early完成)  
dpm_suspended_list → dpm_prepared_list   (resume完成)
dpm_prepared_list → dpm_list             (complete完成)
drivers/base/power/main.c 是 Linux 内核电源管理的核心,它实现了:分阶段的设备电源管理: prepare → suspend → suspend_late → suspend_noirq设备依赖关系处理: 确保父设备和供应商设备的正确顺序异步处理支持: 提高系统挂起/恢复性能多种优化机制: direct_complete、smart_suspend 等完善的错误处理: 看门狗、错误记录、回滚机制这个文件确保了系统中所有设备能够安全、有序地进行电源状态转换,是 Linux 电源管理子系统的基石。
http://www.dtcms.com/a/410660.html

相关文章:

  • 【Android】Android项目目录结构及其作用
  • 动易网站首页制作移动网站排名教程
  • 网站开发和ipv6便宜网站建设 优帮云
  • 前端笔记:HTML output标签介绍及用法
  • Atlas Mapper 教程系列 (6/10):Spring Boot 集成与自动配置
  • 挂马网站现象基于PHP网站开发的管理系统设计与开发
  • DSP28335开发中的Flash与RAM模式切换详解
  • 海珠建网站公石狮网站建设公司哪家好
  • 网站建设电话销售录音建行个人网上登录入口
  • Python全栈项目:基于深度学习的语音识别系统
  • 语音识别-流式和非流式实现方式
  • 网站被攻击 是vps问题还是dz程序建设网站的经验
  • uniapp中pinia(setup语法)使用流程
  • SimpleBEV:改进的激光雷达-摄像头融合架构用于三维目标检测
  • 一个网站制作流程qq快速登录入口
  • Flash Attention学习笔记
  • 解决 QGraphicsDropShadowEffect 导致的 UI 持续刷新
  • 用 LoRA 微调 Qwen3-0.6B 模型,打造专属宠物商店智能客服
  • 建搜索引擎网站衡东网络推广公司
  • Go test 命令完整指南:从基础到高级用法
  • apifox认证登录自动化
  • 江西网站建设哪家专业女装wordpress
  • IDEA JVM优化配置idea64.vmoptions - 保守兼容版本 兼容IDEA 2023.3.6版本【亲测可用】
  • 网站图片像素多少做视频有赚钱的网站
  • APT攻击:隐蔽战场的威胁与防御之道
  • 小兔鲜项目
  • 黑马点评学习笔记01(手机号校验(正则表达式))
  • 声明式事务7
  • 外贸专业网站制作昆明建设网站哪家好
  • 鸿蒙原生contact.queryContacts通讯录查询实现