Power Suspend&Resume

Power Suspend&Resume

@liaoye@2021.5.10

内容目录

power suspend 流程图............................................................................. 1

suspend流程关键点................................................................................. 6

suspend核心:initAutosuspend.......................................................... 7

读取wakeup_count值.................................................................... 8

mSuspendCounter判断................................................................... 9

回写wakeup_count值.................................................................. 10

mem 写入到 state........................................................................ 11

加入LOG分析流程...................................................................... 11

Resume流程....................................................................................... 13

wakeup events framework.................................................................. 14

wakelock和wakeup event framework关系................................. 15

wakeup source & wakeup event & wake lock & wakeup count之间的关系........................................................................................ 16

  1. suspend 流程图

如下图所示,suspend 主要流程:

1、 PowerManagerService.java 灭屏触发Autosuspend 流程

2、SystemSuspend.cpp检测上层/kernel wakelock是否都是释放掉,写入mem到/sys/power/state

3、suspend.c 冻结进程、设备suspend、关闭非启动CPU、关闭中断、syscore休眠、进入WFI、进入芯片相关的低功耗模式(SPM管理、关闭26M CLK 使用32K CLK)

 

 

 

 

 

       

         

         
       

 

  1. 流程关键点

    1. 核心:initAutosuspend

       initAutosuspend函数是suspend流程的核心,是判断需不需要启动suspend流程的起始点,一旦灭屏后就会跑到initAutosuspend函数来。

@system/hardware/interfaces/suspend/1.0/default/SystemSuspend.cpp

 

       initAutosuspend函数只有在第一次灭屏时候执行一次,起了一个线程,这个线程会一直循环读写wakeup_count判断系统中wakelock状态是否符合进入suspend的条件,主要三个工作:读取wakeup_count值、mSuspendCounter判断、回写wakeup_count值和mem 写入到 state

 

      • wakeup_count值

        读取wakeup_count值是已阻塞的方式,只有当前 wakeup events in progress为0(也就是当前没有wakeup event处理)时才会返回。如果有读取成功,判断返回值是否正常,决定是否执行下一步。否则说明有正在处理的wakeup events,则会继续重新读取。

        具体来看下/sys/power/wakeup_count  读操作在kernel中的实现,代码如下:

             @kernel/power/main.c

 

          @driver/base/power/wakeup.c

 

        pm_get_wakeup_count()函数有两个参数,一个是保存返回的count值得指针,另一个指示是否block,具体请参考代码逻辑:

a)如果block为false,直接读取registered wakeup events和wakeup events in progress两个counter值,将registered wakeup events交给第一个参数,并返回wakeup events in progress的状态(若返回false,说明当前有wakeup events正在处理,不适合suspend)。

b)如果block为true,定义一个等待队列,等待wakeup events in progress为0,再返回counter。

***在这里block为true,所以如果有正在处理的wakeup events,read进程会阻塞。其它模块(如auto sleep)发起的read,则可能不需要阻塞。

      1. 判断

代码:mCounterCondVar.wait(counterLock, [this] { return mSuspendCounter == 0; });

mSuspendCounter 是用来记录当前系统中持有多少个上层wakelock,这里代码定义了一个条件等待锁,只有当 mSuspendCounter=0时才会执行下一步,否则会一直阻塞在这里。

      • wakeup_count值

        将读到registered wakeup events count值回写wakeup_count节点,判断返回值是否成功,如果不成功(说明读、写的过程中产生了wakeup events),否则继续读、写,直到成功。

具体来看下/sys/power/wakeup_count  写操作在kernel中的实现,代码如下:

 

 

        这里读取当前registered wakeup events和wakeup events in progress两个counter,并判断registered wakeup events counter是否和之前读取的一致,然后判断wakeup events in progress counter是否为0,如果是,则说明在这段时间中没有新的wakeup event产生,可以进入下一步;否则表示有新的wakeup event产生,会重新执行上述读、写步骤。

 

 

      1. 写入到 state

        若上述流程都成功后,可以触发电源状态切换,也就是mem 写入到 state,正式进入suspend流程。

        调用到kernel正式启动suspend流程,这部分代码逻辑上基本都比较简单,看上述流程图就行,不做详细分析。

      • LOG分析流程

为了更好的理解initAutosuspend的流程,在函数中添加了一些log:

 

 

如下是灭屏后打印出来的log信息:

initAutosuspend()只在第一次灭屏的时候调用一次,在enableAutoSuspend@

com_android_server_power_PowerManagerService.cpp中判断initAutosuspend 是否执行过,启动一个线程

05-11 17:10:19.430   592   598 I android.system.suspend@1.0-service: liaoye start enableAutosuspend: initialized = 0

05-11 17:10:19.430   592   598 I android.system.suspend@1.0-service: liaoye 0: start initAutosuspend

05-11 17:10:19.432   592   598 I android.system.suspend@1.0-service: liaoye 7: end initAutosuspend

05-11 17:10:19.432   592   598 I android.system.suspend@1.0-service: liaoye end enableAutosuspend: initialized = 1

读取 wakeup_count

05-11 17:10:19.532   592  6688 I android.system.suspend@1.0-service: liaoye 1: start read wakeup_count
 

wait lock 等待  mSuspendCounter = 0, 这里为1,所以会一直阻塞

05-11 17:10:29.373   592  6688 I android.system.suspend@1.0-service: liaoye 2: wait lock mSuspendCounter = 1

这里写入失败,重新上述步骤

05-11 17:11:04.095   592  6688 I android.system.suspend@1.0-service: liaoye 3: start write wakeup_count

上述步骤写入失败,重新读去wakeup_count

05-11 17:11:04.196   592  6688 I android.system.suspend@1.0-service: liaoye 1: start read wakeup_count

wait lock 等待  mSuspendCounter = 0, 这里为0,所以会进入下一步

05-11 17:11:04.196   592  6688 I android.system.suspend@1.0-service: liaoye 2: wait lock mSuspendCounter = 0

这里写入成功,继续下一步

05-11 17:11:04.196   592  6688 I android.system.suspend@1.0-service: liaoye 3: start write wakeup_count

写入mem到state,进入suspend 流程

05-11 17:11:04.196   592  6688 I android.system.suspend@1.0-service: liaoye 4: write mem to state

被唤醒或suspend失败

05-11 17:11:29.246   592  6688 I android.system.suspend@1.0-service: liaoye 5: wakeup

05-11 17:11:29.247   592  6688 I android.system.suspend@1.0-service: liaoye 6

又开始新一轮循环

05-11 17:11:29.349   592  6688 I android.system.suspend@1.0-service: liaoye 1: start read wakeup_count

    1. 流程

        resume流程基本和suspend流程是相反的,这里主要讲下从外部中断是如何产生的呢?又是如何唤醒系统的呢?

        一般具有中断唤醒的设备会有一个interrupt pin硬件连接到SoC的gpio pin。一般来说,当设备需要唤醒系统的时候,会通过改变interrupt pin电平状态,而SoC会检测到这个变化,将SoC从睡眠中唤醒,唤醒走的与suspend相反的流程,当完成resume irq流程后会执行该设备注册中断服务程序,对该设备的中断事件做出对应的处理。

        为了使能设备的唤醒能力,设备驱动中会在系统suspend的时候通过enable_irq_wake(irq)接口使能设备SoC引脚的中断唤醒能力,也就是对中断控制器的寄存器进行配置对应irq使能唤醒能力。

    1. events framework

       wakeup events framework 始终贯穿着suspend整个流程,这里了解下wakeup events framework 及在suspend流程中的作用。

 

 

1、wakeup events framework core,在drivers/base/power/wakeup.c中实现,提供了wakeup events framework的核心功能:

抽象wakeup sourcewakeup event的概念;

向各个device driver提供wakeup source的注册、使能等接口;

向各个device driver提供wakeup event的上报、停止等接口;

向上层的PM core(包括wakeup countauto sleepsuspendhibernate等模块)提供wakeup event的查询接口,以判断是否可以suspend、是否需要终止正在进行的suspend

2、wakeup events framework sysfs,将设备的wakeup信息,以sysfs的形式提供到用户空间,供用户空间程序查询、配置。在drivers/base/power/sysfs.c中实现。

3、wake lock/unlock,为了兼容Android旧的wakeup lock机制而留下的一个后门,扩展wakeup events framework的功能,允许用户空间程序报告/停止wakeup events。换句话说,该后门允许用户空间的任一程序决定系统是否可以休眠。

4、wakeup count,基于wakeup events framework,解决用户空间同步的问题。

5、auto sleep,允许系统在没有活动时(即一段时间内,没有产生wakeup event),自动休眠。

上部分引用:http://www.wowotech.net/linux_kenrel/wakeup_events_framework.html

      1. 和wakeup event framework关系

       简单来说wakeup event framework是wakelock的底层实现,wakelock提供接口给其他模块调用。其中wakelock包括两类:

       上层wakelock:上层framework实现供上层的模块的使用,通过wake_lock和wake_unlock节点调用到kernel 实现的接口,最终都会调用到__pm_stay_awake()@wakeup.c

       kernel wakelock:供kernel层的模块使用,最终都会调用到__pm_stay_awake()@wakeup.c

       __pm_stay_awake()→ wakeup_source_report_event()→ wakeup_source_activate(), wakeup_source_activate()函数实现如下:

       作用是对combined_event_count变量增加一次计数,combined_event_count是个比较重要的变量,作用是用来保存registered wakeup events和wakeup events in progress两个计数,initAutosuspend函数也是通过/sys/power/wake_count节点最终读取到combined_event_count来进行判断系统中wakeup event状态是否能进入suspend流程。

registered wakeup events记录了系统运行以来产生的所有wakeup event的个数,wakeup events in progress处理完成wakeunlock时加1;

@wakeup_source_deactivate()

wakeup events in progress记录正在处理的wakeup event个数,在wakelock时加1;

@wakeup_source_activate()

combined_event_count是上述两个计数的组合,是一个32位的it,前16位用于registered wakeup events,后16位用于wakeup events in progress。

      1. source & wakeup event & wake lock & wakeup count之间的关系

       从上图可以看出,不管是上层还是底层申请wakelock,最终都会记录到combined_event_count

,而combined_event_count是作为是否启动suspend流程和判断suspend流程中是否产生新的wakeup event 需要退出suspend流程的重要条件。

eof

  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值