- Android系统级深入开发
- 韩超 梁泉
- 1137字
- 2020-08-26 21:43:41
4.3.1 wakelock和earlysuspend
wakelock是Android提供的一种特殊的机制,用于请求CPU资源。当持有wakelock之后,可以阻止系统进入暂停或其他低功耗状态。
wakelock和earlysuspend的头文件在include/linux/目录中,实现的内容在kernel/power/目录中,其Makefile组织如下所示:
obj-$(CONFIG_FREEZER) += process.o obj-$(CONFIG_WAKELOCK) += wakelock.o obj-$(CONFIG_USER_WAKELOCK) += userwakelock.o obj-$(CONFIG_EARLYSUSPEND) += earlysuspend.o obj-$(CONFIG_CONSOLE_EARLYSUSPEND) += consoleearlysuspend.o obj-$(CONFIG_FB_EARLYSUSPEND) += fbearlysuspend.o
wakelock.c是wakelock的核心实现。userwakelock.c是在用户空间使用wakelock的接口实现。earlysuspend.c是earlysuspend机制的核心实现。consoleearlysuspend.c和fbearlysuspend.c是console和framebuffer在处理earlysuspend时的具体实现。
wakelock的接口定义的常量在wakelock.h中,内容如下所示:
enum { WAKE_LOCK_SUSPEND, /* 阻止挂起 */ WAKE_LOCK_IDLE, /* 阻止低能耗的Idel */ WAKE_LOCK_TYPE_COUNT };
该枚举定义了wakelock的种类。WAKE_LOCK_SUSPEND用于阻止系统进入suspend状态(CPU挂起),一般是深度休眠,Android提供了通用实现。WAKE_LOCK_IDLE用于阻止系统进入idle状态(CPU低功耗运转),一般在需要比较多的计算资源时候,申请此wakelock,各家芯片商对该wakelock的底层实现可以不一样。
wakelock的接口如下所示:
void wake_lock_init(struct wake_lock *lock, int type, const char *name); void wake_lock_destroy(struct wake_lock *lock); void wake_lock(struct wake_lock *lock); void wake_lock_timeout(struct wake_lock *lock, long timeout); void wake_unlock(struct wake_lock *lock);
wake_lock_init对应wake_lock_destroy。用于创建和销毁一个wakelock。wake_lock和wake_unlock对应,用于持有和释放一个wakelock。wake_unlock持有一个带超时机制的wake_lock,会在超时后自动unlock。
以上接口主要用于内核空间驱动程序等使用。很多驱动程序使用wakelock来阻止CPU进入休眠,以完成关键传输。
在用户空间中,可以通过userwakelock.c中基于此实现的接口来调用。wakelock在用户空间的接口为Sys文件系统的/sys/power/wake_lock和/sys/power/wake_unlock。通过对其的写入,读出操作,完成持有,释放等操作。
Android系统电源管理功能,通过这里的接口,把wakelock暴露给用户空间的应用程序。
wakelock机制与earlysuspend(早期挂起)结合,形成Android独有的电源管理机制。后者通过在linux标准的suspend前,resume后这两个环节分别插入earlysuspend,lateresume来实现。
earlysuspend其实是一个完全挂起前中间状态。简单的来说,该状态下,屏幕和背光关闭,不响应诸如传感器和触摸屏的事件。该状态对于移动设备来说是非常常见的,比如关闭屏幕播放音乐等。而标准Linux中并没有该状态,因此Android进行了扩充。
扩充earlysuspend以后,原有的挂起操作(例如:在用户空间向/sys/power/state中写入“mem”的操作),并不直接将kernel挂起。而是进入earlysuspend,直到最后一个wakelock被释放,再进入原kernel的挂起流程。
例如,应用上述机制,音乐播放的模式就比较容易实现。只需要一直持有wakelock,即可停留在earlysuspend模式,屏幕背光可以被关闭实现省电,而CPU被占有继续进行播放工作。
earlysuspend主要提供了如下的接口:
struct early_suspend { #ifdef CONFIG_HAS_EARLYSUSPEND struct list_head link; int level; void (*suspend)(struct early_suspend *h); void (*resume)(struct early_suspend *h); #endif }; #ifdef CONFIG_HAS_EARLYSUSPEND void register_early_suspend(struct early_suspend *handler); void unregister_early_suspend(struct early_suspend *handler); #else #define register_early_suspend(handler) do { } while (0) #define unregister_early_suspend(handler) do { } while (0) #endif
以上函数用于各驱动程序实现并注册各自的发生early_suspend和late_resume时候的处理功能。
consoleearlysuspend和fbearlysuspend实现了console和framebuffer处理early_suspend和late_resume时的处理函数。并暴露了用户空间接口,以和Android系统框架进行交互,判断是否需要继续绘制屏幕。
提示:在编写传感器、触摸屏、背光等设备驱动程序时,为了能源管理的处理,可以先注册相应的early_suspend和late_resume处理函数。
从实现上来看,Android的wakelock和earlysuspend机制,在一定程度上改变了Linux原有的电源管理机制。同时,将强制占有CPU而不允许挂起的能力赋予应用程序,有可能对省电管理问题造成混乱。