STR介绍

1. STR概述

STR是Suspend To Ram的简写,STR是一种可以快速恢复系统运行状态的待机模式,系统在待机前将程序的运行上下文保存在内存中,待机时主芯片下电,内存进入自刷新模式(Self-Refresh)状态以降低功耗,唤醒后再将程序运行上下文恢复,以此实现迅速恢复到待机前运行状态的功能。STR对应ACPI(Advanced Configuration and Power Management Interface)中的S3状态,S3定义为Suspend to RAM(mem),CPU is Off,RAM is powered and the running content is saved to RAM。

STR能大幅提高Android系统的唤醒速度,可将Android系统的启动时间从20s以上降低到5s以下,显著改善用户体验,同时可以保持很低的待机功耗。

STR功能的核心是保存和恢复系统状态,恢复程序运行环境。从待机状态唤醒并恢复到此前的运行状态,关键是将待机前的软硬件环境完整的恢复,包括电源时钟、CPU、业务逻辑、存储设备、外设等。STR功能的实现需要芯片、硬件、软件的相互配合。

2. STR流程

Android待机流程

Android待机接口调用流程

Android待机首先从按键处理开始,PhoneWindowManager会处理用户按键(短按的入口在powerPress,长按的入口在powerLongPress),如果是待机键,会调用PowerManagerService的goToSleep方法进行待机处理。PowerManagerService会广播通知各个模块进行待机,然后Android的各个模块释放Wakelock(Wakelock:唤醒锁定,简称唤醒锁,持有唤醒锁的模块就不会进入待机)。待所有Wakelock被释放后,Android会通知kernel进行待机。

Android SystemSuspend Service流程

从Android10开始,SystemSuspend服务取代了libsuspend(在 Android 9 及更低版本中,libsuspend 中有一个负责发起系统挂起的线程。Android 10 在 SystemSuspend HIDL 服务中引入了等效功能)。执行线程在system/hardware/interfaces/suspend/1.0/default/SystemSuspend.cpp。

SystemSuspend 服务使用挂起计数器跟踪发出的唤醒锁数量。它有两个执行线程:

  • 主线程响应 binder 调用。

  • 挂起线程控制系统挂起。

主线程

主线程响应来自客户端的请求以分配新的唤醒锁,从而递增/递减挂起计数器。

挂起线程

挂起线程循环执行以下操作:

  1. 从 /sys/power/wakeup_count 读取。

  2. 获取互斥量。这可确保挂起线程在主线程尝试递增或递减挂起计数器时不会触发挂起计数器。如果挂起计数器达到零,并且挂起线程尝试运行,则系统会在发出或移除唤醒锁定时阻止主线程。

  3. 等到计数器等于零。

  4. 将从 /sys/power /wakeup_count(第 1 步中)读取的值写入此文件。 如果写入失败,则返回到循环的开头。

  5. 通过将 mem 写入 /sys/power/state 来发起系统挂起。

  6. 释放互斥量。

SystemSuspend API 包含两个接口。HIDL 接口由原生进程用于获取唤醒锁,而 AIDL 接口则用于在 SystemServer 和 SystemSuspend 之间通信。

SigmaStar平台的STR开关机流程

目前平台在工厂菜单中通过Other Options-Enable STR设置STR开关,

Enable STR为on时,短按power键系统进入Suspend。

Enable STR为off时,短按power键系统进入熄屏。

3. STR常见问题及调试

3.1. 无法待机

3.1.1. Android待机流程未启动

若按下遥控器的Power键,系统没有进入待机,则首先检查待机流程是否启动,一般是通过logcat查看PhonWindowManager和PowerManagerService相关打印,如power key是否有收到,是否关屏,是否Going to sleep。

WindowManager: powerPress: eventTime=57435 interactive=true count=0 beganFromNonInteractive=false mShortPressOnPowerBehavior=1
PowerManagerService: Powering off display group due to power_button (groupId= 0, uid= 1000)...
PowerManagerService: Going to sleep due to power_button (uid 1000)...

分析STR待机异常时,可以将PhonWindowManager和PowerManagerService的log打开

public class PhoneWindowManager implements WindowManagerPolicy {
    static final String TAG = "WindowManager";
    static final boolean localLOGV = true;//false;
    static final boolean DEBUG_INPUT = true;//false;
    static final boolean DEBUG_KEYGUARD = true;//false;
    static final boolean DEBUG_SPLASH_SCREEN = true;//false;
    static final boolean DEBUG_WAKEUP = true;//false;
    static final boolean SHOW_SPLASH_SCREENS = true;//true;
public final class PowerManagerService extends SystemService
        implements Watchdog.Monitor {
    private static final String TAG = "PowerManagerService";

    private static final boolean DEBUG = true;//false;
    private static final boolean DEBUG_SPEW = DEBUG && true;

3.1.2. 没有进入内核待机流程

【STR待机Log】

PM: suspend entry (deep)
Filesystems sync: 0.019 seconds
Freezing user space processes ...
Freezing remaining freezable tasks ... (elapsed 0.001 seconds) done.
printk: Suspending console(s) (use no_console_suspend to debug)

如果没有以上信息,则说明没有进入内核待机流程。进入内核待机流程的入口是SystemSuspend,在SystemSuspend会根据上层释放完所有的唤醒锁后执行echo mem > /sys/power/state触发进入内核待机流程。一般可以通过打开Logcat开关进行排查。

3.1.3. 快速按Power键无法进入待机

需要通过Logcat查看无法进入待机的原因,如如下log,系统原生会判断快速的电源键操作用来启动摄像头从而会影响待机。

PowerManagerService: Going to sleep due to power_button (uid 1000)...
GestureLauncherService: Power button double tap gesture detected, launching camera. Interval=190ms

PowerManagerService: Powering on display group fromDozing (groupId=0, uid=1000, reason=WAKE_REASON_CAMERA_LAUNCH, details=com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK)...

PowerManagerService: Waking up from Dozing (uid=1000, reason=WAKE_REASON_CAMERA_LAUNCH, details=com.android.systemui:CAMERA_GESTURE_PREVENT_LOCK)...

Keyevent处理时会申请wakelock,如果Keyevent没有及时响应,也可能会阻碍待机,此时需要去掉Keyeventde的wakelock。

3.1.4. 内核驱动阻止待机

通过log查看待机log打印,搜索suspend fail或call trace相关,一般可以看出哪个模块suspend fail影响到了内核待机。可通过在fastboot里设置no_console_suspend=1查看更多的待机打印。

3.2. 无法唤醒

【STR开机Log】

E:CD
CPU=1000Mhz

IPL g700bff1
D-20
HW Reset
Resume!!!!
DDR4 3200 16Gb
MIU Init Android Enhance!
Force miupll_466MHz
Restore Flash setting for STR
Restore Miu setting for STR
GICv3: CPU0: found redistributor 0 region 0:0x0000000016040000
Enabling non-boot CPUs ...
Detected VIPT I-cache on CPU1
GICv3: CPU1: found redistributor 100 region 0:0x0000000016060000
CPU1: Booted secondary processor 0x0000000100 [0x412fd050]
CPU1 is up
Detected VIPT I-cache on CPU2
GICv3: CPU2: found redistributor 200 region 0:0x0000000016080000
CPU2: Booted secondary processor 0x0000000200 [0x412fd050]
CPU2 is up
Detected VIPT I-cache on CPU3
GICv3: CPU3: found redistributor 300 region 0:0x00000000160a0000
CPU3: Booted secondary processor 0x0000000300 [0x412fd050]
CPU3 is up

正常STR唤醒后会输出如上log。

STR待机后,设备进入MCU,等待外界唤醒,若无法唤醒,则需确认唤醒键值是否配置正确,遥控器发出的码值是否MCU支持。

3.3. STR压力测试

STR压力测试出现的问题,一般需要通过logcat定位具体问题,同时考虑是否有内存泄漏的问题存在与否。

3.4. 常用的调试命令

1.查看系统待机相关服务是否正常运行。

console:/ # service list | grep suspend
164  suspend_control: [android.system.suspend.ISuspendControlService]
165  suspend_control_internal: [android.system.suspend.internal.ISuspendControlServiceInternal]

2.查看设备的睡眠状态,通过echo mem > /sys/power/state可让系统直接进入内核待机流程。

cat sys/power/state

3.查看所有锁住和未锁住的wakelock的名字,如有应用持锁待机一直不释放,则系统将无法进入休眠模式。

cat /sys/power/wake_lock
cat /sys/power/wake_unlock

4.查看WAKELOCK STATS。

dumpsys suspend_control_internal