之前介绍的电源管理机制基本都是在Linux中实现的,可以看到很复杂,各种框架,明明一个操作非要转来转去,而且在内核里面实现,跟内核的各种框架又纠缠不清,什么consumer、Framework、provider框架乱乱的。就不能搞成最简单的CS构架,一个Client和一个Server就搞定了,不需要什么框架,也不需要跟各种程序混到一块去,就像上图的一个问题:去饭店吃饭是客户端还是服务端?
问题的解决方案直指微内核,关于微内核的介绍,之前有文章:XXX
这里以QNX为例,介绍下微内核中的电源管理的特点:
- 电源管理作为一个server在用户层,算一个app
- 电源管理服务的对象Client:电源敏感app、驱动app、电源监控程序
- Client和Server之间通过IPC通信,约定好通信的报文
1. QNX电源管理框架
- 可以控制各个设备包括CPU的电源状态
- 一组电源管理服务,用于实现电源管理策略,可以管理应用APP即设备硬件驱动APP
电源管理架构的主要组件是:
- 实施系统电源管理策略的电源管理服务
- 与电源管理器交互以根据系统策略调整功率级别的设备驱动程序
- 电源监控应用程序------可以提供电源管理策略使用的输入事件或数据
- 功率敏感应用程序------可能会收到电源模式更改的通知。
QNX中一切都是文件,设备也是组织为文件层级,对设备的电源管理操作就是操作文件节点,例如上图中。
电源管理状态:
对于设备只定义了四种,简单好管理。 - **Active** *:* 表示从用户的角度来看实体是可操作的。 - **Idle** *:* 表示实体部分供电;并非所有功能都可操作。从用户的角度来看,实体是可操作的,并在使用时转换为*活动*模式。 - **Standby** *:* 表示实体部分供电;只有有限的功能是可操作的,例如实现唤醒事件。从用户的角度来看,该实体是不可操作的。 - **Off** *:* 指示实体已断电且不可操作。
对于系统可以多定义一些层级,用来进入不同级别的节电状态,例如上图中的车载远程信息处理系统的不同电源模式。
上图显示电源管理策略通过在空闲、待机(睡眠)或关机状态之间转换来逐步关闭设备。这用于限制从电池汲取的待机电流在点火装置关闭时逐渐下降。该系统还可以随时准备在短时间内启动。例如,实时时钟 (RTC) 可用于定时唤醒 CPU 休眠模式。
当汽车熄火后,像CPU、SDRAM、RF、RTC等设备不能立即断电,因为CPU、SDRAM是保持系统处于一个运行状态,而RF、RTC是系统唤醒源。
总结如下:
- Power Manager初始化 先调用pmm_init()初始化命名空间,及power manager 提供的resource manager接口; 调用pmm_start()初始化处理client请求的thread; 触发各个device driver or service启动,; 启动其他client:system monitoring apps, Power sensitive apps;
- 各个device driver or service启动过程中会向power manager注册
- System monitoring apps 中的关火检测线程检测到关火事件,则将当前的点火系统为off的状态作为属性发送给power manager; Power manager得知system monitor app 汇报了点火系统关闭的,会执行相应的电源管理策略,切换当前电源模式;将Active1 Idle; 切换电源模式具体操作:对Audio、Video设备执行电源模式切换,此操作为异步操作。
- Audio、Video设备驱动内部执行电源模式切换:Active->Shutdown, 当执行完毕后向Power manager发送设备电源模式切换完成的event;同时会触发对设备及系统电源模式切换关心的app即Power sensitive apps发送event;
- 对设备及系统电源模式切换关心的Power sensitive apps执行相应的处理。
2. QNX客户端API库
驱动程序API:
客户端库提供了允许驱动程序和电源管理服务之间双向通信的基本服务:
- 驱动程序初始化时需要向电源管理服务进行注册,这样系统电源状态更改才去通知这个驱动
- 电源管理服务根据系统电源模式策略通知驱动程序更改电源模式。
- 驱动程序向电源管理服务报告其电源模式状态。
- 驱动程序可以选择向电源管理服务请求自主电源模式更改。
参考:http://myqnx.com/developers/docs/6.3.0SP3/power_mgmt_en/user_guide/ddriver.html
功耗敏感程序API:
- 功耗敏感程序要想电源管理服务注册感兴趣的系统电源状态或者某个设备的电源状态
- 接收电源模式更改的通知
- 查询特定服务或驱动程序的电源模式
- 请求更改特定服务或驱动程序的电源模式。
系统监控应用程序的API:
- 系统监控程序需要给电源管理服务上板各种参数,例如电量、温度等。
- 管理与电源管理器对象关联的属性。这些属性可以包括由产品特定系统电源管理策略处理的任意数据,以确定最合适的电源模式
- 根据自己的评估标准请求特定服务或驱动程序的电源模式更改。
例如查询设备自己的电源模式:
perl
pm_power_attr_t attr;
if (pm_getattr(hdl, &attr) == -1) {
error...
}
printf("Current mode is %d\n", attr.cur_mode);
if (attr.new_mode != attr.cur_mode)
printf("Device is changing modes to %d\n", attr.new_mode);
if (attr.nxt_mode != attr.new_mode)
printf("Pending mode change to %d\n", attr.nxt_mode);
改变电源模式:
scss
int status;
// attempt to change mode, subject to the power manager policy
if (pm_setmode(hdl, mode, 0) == -1) {
if (errno == EACCES) {
// force the power mode to change
pm_setmode(hdl, mode, PM_MODE_FORCE);
} else {
error...
}
}
3. QNX代码分析
这里以关机为例: shutdown:关机或重启之前会正确地中止进程及服务,代码路径:utils\s\shutdown\main.c
- 先对命令参数进行解析:-b是重启 -S r是重启
- 调用库函数shutdown_system()进行重启
库函数shutdown_system(),代码路径:lib\shutdown\shutdown.c
- 提高进程优先级
- 根据"/proc"目录下进程,构建所有正在运行的进程的列表,申请内存空间pidvec存放
- 按进程的class值排序,然后顺序发送SIGTERM来关闭进程,kill(pip->pid, SIGTERM)
- 等待一段时间直到进程被杀死为止,如果时间到了还没杀死且class <= CLASS_APP则发送SIGKILL信号
- 此时,所有非显示过程都已关闭。 调用shutdown_done()函数做显示更新
- 如果是重启,则调用sysmgr_reboot
- 释放pidvec内存空间
sysmgr_reboot()函数,代码中位置:lib\c\services\sysmgr_reboot.c
ini
int sysmgr_reboot(void) {
sys_cmd_t msg;
msg.i.type = _SYS_CMD;
msg.i.cmd = _SYS_CMD_REBOOT;
return MsgSendnc(SYSMGR_COID, &msg.i, sizeof msg.i, 0, 0);
}
services\system\ker\miniproc_start.c中do_miniproc()函数进行处理
arduino
case _SYS_CMD_REBOOT:
RebootSystem(0);
break;
之后执行services\system\ker\kerext_reboot.c中reboot()函数
scss
static void
reboot(void *abnormal) {
lock_kernel();
cpu_reboot();
calloutptr->reboot(_syspage_ptr, (int)abnormal);
}
- 屏蔽内核中断
- 执行cpu重启
- 回调calloutptr->reboot函数
4. Fuchsia中的电源管理
Fuchsia也是微内核架构,见之前的文章介绍:XXX
电源管理官方介绍:Device power management
在代码中的位置:src/power/power-manager/src
代码是用Rust语言写的
查看代码使用网站:cs.opensource.google/fuchsia/fuc...
初始化:
src/power/power-manager/src/main.rs中找到main函数
rust
async fn main() -> Result<(), Error> {
// Setup logging
fuchsia_syslog::init()?;
log::info!("started");
// Setup tracing
fuchsia_trace_provider::trace_provider_create_with_fdio();
// Set up the PowerManager
let mut pm = PowerManager::new();
// This future should never complete
let result = pm.run().await;
log::error!("Unexpected exit with result: {:?}", result);
result
}
run函数在模块PowerManager中
rust
/// Perform the node initialization and begin running the PowerManager.
pub async fn run(&mut self) -> Result<(), Error> {
// Create a new ServiceFs to handle incoming service requests for the various services that the PowerManager hosts.
let mut fs = ServiceFs::new_local();
// Allow our services to be discovered.
fs.take_and_serve_directory_handle()?;
// Required call to serve the inspect tree
let inspector = component::inspector();
inspect_runtime::serve(inspector, &mut fs)?;
// Create the nodes according to the config file
let node_futures = FuturesUnordered::new();
self.create_nodes_from_config(&mut fs, &node_futures).await?;
// Run the ServiceFs (handles incoming request streams) and node futures. This future never completes.
futures::stream::select(fs, node_futures).collect::<()>().await;
Ok(())
}
SystemPowerModeHandler
这里有很多种type,例如电源模式"SystemPowerModeHandler",主要执行了new_from_json 和build这两个函数
SystemShutdownHandler
每个类型的Handler调用new_from_json
函数将json文件中的配置赋给handler结构体,然后调用build
方法,初始化handler实例,启动服务线程。
这里不详细说明了,大家可以自己去看代码。
5. Minix中的电源管理
Minix也是一个微内核,介绍见之前的文章:XXX,有兴趣自己看看代码。
6. Harmony OS中的电源管理
Harmony OS也是一个微内核,详见之前的文章:XXX,有兴趣的可以自己看看代码。
关机相关:services/native/src/shutdown_service.cpp
docs.openharmony.cn/pages/v3.2B...
电源管理服务组件提供如下功能:
- 重启系统。
- 管理休眠运行锁。
- 系统电源状态查询。
后记:
微内核中电源管理和各种驱动都被实现为APP,各种应用APP一般之前是根据Linux开发的,也不可能在微内核上重新开发一遍,那这些应用APP是符合UNIX编程函数规范的,也就是符合POSIX规范,一个最大的特点就是其规定了一系列的系统调用支持这些应用APP。那么在微内核中需要再加一个壳子来提供这些POSIX接口,从而扩展微内核支持的系统调用,不在微内核中的电源管理和驱动等需要跟这个壳子交互来对应用提供服务,或者直接跟电源管理和驱动的server APP交互(需要重写应用APP的代码接口)。
干啥都能干,干啥啥不是,
专业入门劝退,堪称程序员杂家"。
欢迎各位有自己公众号的留言:申请转载,多谢!
后续会继续更新,纯干货分析,欢迎分享给朋友,欢迎点赞、收藏、在看、划线和评论交流!