Android休眠流程
- 概述
设备的休眠是功耗分析中的重要篇章,有些问题经常会涉及到系统无法休眠,经常被唤醒等情况。在这里将从代码角度来分析下Android系统休眠和唤醒的机制,而本篇将着重阐述休眠机制。
Android系统的电源管理子系统是已Linux的电源管理系统为基础,针对现实问题又进行了改造,而这里的现实问题来自于PC和移动设备的差异,其核心在于什么时候休眠,什么时候唤醒。在PC系统中,什么时候让系统进入休眠(通常是STR、Standby、Hibernate等suspend操作)这个问题很容易理解:答案就是由用户在其不再使用时触发。
然而移动设备的特性决定了用户可能随时随地会使用设备,那么休眠的时机就变得非常不明确了。于是Android上提出了Opportunistic suspend这个概念,通俗的讲就是逮住机会就赶紧休眠一会儿直到下次被唤醒,而这个机会就是系统没有任务需要处理的时候。由此就衍生除了autosleep机制和wake source的概念。Android的休眠是一种自动休眠,当系统中不存在唤醒源时就进行系统整体休眠。相比于Linux内核中复杂的单独模块休眠管理(Dynamic PM),Android的此套设计方式简单粗暴,但是实实在在的解决了移动设备上面临的燃眉之急。
2.自动休眠
2. 1.Frameworks层
备注:自动休眠一定不能插上usb抓取log,因插上usb不会进入休眠模式。
系统休眠又用户主动发起的关系并不是很大,在用户和应用的行为中,主动通过power键发起灭屏或者是调用PowerManager的goToSleep接口来进行系统休眠是较常用的操作,其他也没有更多的手段。而系统休眠大多是系统主动检测并发起休眠流程,所以本篇中就不涉及上层的流程了,直接从Frameworks开始。
Frameworks层这部分的设计思想比较简单,主要是:电源管理通过监测display的状态,当灭屏时则发起休眠的流程,调用native层的方法继续往下走。这里就很好的体现了前文提到的Opportunistic suspend概念,伺机休眠这里的“机”的第一层就是以灭屏作为契机的。果然是简单粗暴的判断,但是非常实用,从用户角度来将,灭屏的现象确实是让设备休眠的理想触发。当然,在灭屏时需要后台处理任务的情况也是存在,所以在后面流程中会继续判断是否真正能够进入休眠。接下来从代码角度解读下frameworks层的实现。
流程就先从灭屏开始看,系统中除了PowerManagerService外还有个叫做DisplayManagerService的核心服务来管理display相关的电源状态,它也是在SystemServer中启动起来的。在PowerManagerService中systemReady方法中会去初始化DisplayManagerService
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
// Initialize display power management. mDisplayManagerInternal.initPowerManagement( mDisplayPowerCallbacks, mHandler, sensorManager);
DisplayManagerService中的initPowerManagement相关部分如下:
private final class LocalService extends DisplayManagerInternal { @Override public void initPowerManagement(final DisplayPowerCallbacks callbacks, Handler handler, SensorManager sensorManager) { synchronized (mSyncRoot) { DisplayBlanker blanker = new DisplayBlanker() { @Override public void requestDisplayState(int state, int brightness) { // The order of operations is important for legacy reasons. if (state == Display.STATE_OFF) { requestGlobalDisplayStateInternal(state, brightness); } callbacks.onDisplayStateChange(state); if (state != Display.STATE_OFF) { requestGlobalDisplayStateInternal(state, brightness); } } }; mDisplayPowerController = new DisplayPowerController( mContext, callbacks, handler, sensorManager, blanker); } mHandler.sendEmptyMessage(MSG_LOAD_BRIGHTNESS_CONFIGURATION); }
实现了DisplayBlanker接口,并重写了其requestDisplayState方法,在此方法中又调用DisplayPowerCallbacks接口的onDisplayStateChange方法来进行display发生变化之后的操作。这一段为整个frameworks流程中的核心部分也是流程的中间部分,接下来补上它的头和尾。
首先是display改变的消息传递,也就是代码流程中如何会调用到DisplayBlanker接口的requestDisplayState,来看图就可以了:
首先是在DisplayPowerController中收到MSG_UPDATE_POWER_STATE消息,随后经过一系列的回调了DisplayBlanker接口的requestDisplayState,其中每个细节不是这里的重点就不展开一一分析了。然后是尾,DisplayPowerCallbacks接口的onDisplayStateChange方法在PowerManagerService中
public void onDisplayStateChange(int state) { // This method is only needed to support legacy display blanking behavior // where the display's power state is coupled to suspend or to the power HAL. // The order of operations matters here. synchronized (mLock) { if (mDisplayState != state) {// display的状态发生改变 mDisplayState = state; if (state == Display.STATE_OFF) {// 灭屏 if (!mDecoupleHalInteractiveModeFromDisplayConfig) {// 默认false setHalInteractiveModeLocked(false);// 关闭交互模式 } if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) {// 默认false setHalAutoSuspendModeLocked(true);// 开启autosleep模式 } } else {// 亮屏 if (!mDecoupleHalAutoSuspendModeFromDisplayConfig) { setHalAutoSuspendModeLocked(false);// 关闭autosleep模式 } if (!mDecoupleHalInteractiveModeFromDisplayConfig) { setHalInteractiveModeLocked(true);// 开启交互模式 } } } } }
这一段中有一个非常重要的核心:前面提到了将灭屏作为休眠发起的条件,也就是说将灭屏和休眠作为了耦合的关系,而这里提供了解耦的操作,可以在代码配置中来选择是否要解耦。判断的依据就是mDecoupleHalAutoSuspendModeFromDisplayConfig这个变量,它的默认值定义在frameworks/base/core/res/res/values/config.xml中:
false
解读:默认情况下将suspend流程和display的状态耦合在一起,默认为false(不解耦),在默认情况下,在屏幕off之后调用启用autosuspend,在屏幕on之前关闭autosuspend_enable。而如果解耦,那么suspend的流程将被独立调用而不管屏幕状态,在此模式下就算是屏幕on也允许系统休眠。
这一段代码中还包括了另外一个操作,setHalInteractiveModeLocked来设置系统可交互模式,由mDecoupleHalInteractiveModeFromDisplayConfig这个变量来控制和display的耦合关系。同样附上这个默认值的定义:
false
解读:这里描述了系统的可交互模式和display的耦合关系。当设置为false时,两者为耦合的关系,在display状态on之前setInteractive(…, true)设置为可交互;在display状态为off之后设置为不可交互。而如果为解耦状态,那么交互模式也将可以被独立设置不论display的状态如何。
我们还是来继续看auto sleep的流程,当灭屏时,调用PowerManagerService的setHalAutoSuspendModeLocked(true)
frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
private void setHalAutoSuspendModeLocked(boolean enable) { if (enable != mHalAutoSuspendModeEnabled) { if (DEBUG) { Slog.d(TAG, "Setting HAL auto-suspend mode to " + enable); } mHalAutoSuspendModeEnabled = enable; Trace.traceBegin(Trace.TRACE_TAG_POWER, "setHalAutoSuspend(" + enable + ")"); try { mNativeWrapper.nativeSetAutoSuspend(enable); } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); } } }
这里只是做了些判断和加调试代码,然后将流程通过nativeSetAutoSuspend带入到了native库中。
2.2. Native层
根据JNI的机制可以找到代码进入到了com_android_server_power_PowerManagerService.cpp中的nativeSetAutoSuspend中:
frameworks/base/services/core/jni/com_android_server_power_PowerManagerService.cpp
static void nativeSetAutoSuspend(JNIEnv* /* env /, jclass / clazz */, jboolean enable) {
if (enable) {
android::base::Timer t;
enableAutoSuspend();
if (t.duration() > 100ms) {
ALOGD(“Excessive delay in autosuspend_enable() while turning screen off”);
}
} else {
android::base::Timer t;
disableAutoSuspend();
if (t.duration() > 100ms) {
ALOGD(“Excessive delay in autosuspend_disable() while turning screen on”);
}
}
}
当灭屏时(默认情况下)调用autosuspend_enable(),然后进一步的实现在hal文件中,源代码位于system/hardware/interfaces/suspend/1.0/default/目录下。
2.2.1 休眠机制初始化
来看一下开启自动挂起模式的实现方法——enableAutoSuspend
com_android_server_power_PowerManagerService.cpp
void enableAutoSuspend() {
static bool enabled = false;
//suspendService != nullptr && suspendService->enableAutosuspend():从后面的代码可以看到这个值决定了enlable的值,在开机执行一次
if (!enabled) {
sp suspendControl = getSuspendControl();
suspendControl->enableAutosuspend(&enabled);
}
{ std::lock_guard lock(gSuspendMutex); if (gSuspendBlocker) { gSuspendBlocker->release(); gSuspendBlocker.clear(); } }
}
sp getSuspendControl() {
static std::once_flag suspendControlFlag;
std::call_once(suspendControlFlag, {
while(gSuspendControl == nullptr) {
sp control =
defaultServiceManager()->getService(String16(“suspend_control”));
if (control != nullptr) {
gSuspendControl = interface_cast(control);
}
}
});
return gSuspendControl;
}
这里有一个难点,通过getSuspendControl方法获得的ISuspendControlService实现类是什么? 请注意getSuspendControl方法里的这条语句: defaultServiceManager()->getService(String16(“suspend_control”)),这是一个典型的Binder调用,它请求了服务名称为 suspend_control 的远端服务。注册名称为suspend_control的服务到底是谁,我们可以在/system/hardware/interfaces/suspend/1.0/default/main.cpp中找到答案。
sp suspendControl = new SuspendControlService();
auto controlStatus = android::defaultServiceManager()->addService(
android::String16(“suspend_control”), suspendControl);
可以清楚的看到,SuspendControlService就是我们要寻找的答案。
SuspendControlService.cpp
binder::Status SuspendControlService::enableAutosuspend(bool* _aidl_return) {
//wp 升级为 sp,这条语句牵涉到 android 智能指针相关的知识点 promote方法可以将弱指针升级为强指针
const auto suspendService = mSuspend.promote();
//调用到了 SystemSuspend.cpp 的enableAutosuspend 方法
return retOk(suspendService != nullptr && suspendService->enableAutosuspend(), _aidl_return);
}
SuspendControlService.cpp
binder::Status retOk(const T& value, T* ret_val) {
*ret_val = value;
return binder::Status::ok();
}
SystemSuspend.cpp
bool SystemSuspend::enableAutosuspend() {
static bool initialized = false;
if (initialized) {
LOG(ERROR)