Android休眠流程

2024-06-04 7242阅读
  1. 概述

    设备的休眠是功耗分析中的重要篇章,有些问题经常会涉及到系统无法休眠,经常被唤醒等情况。在这里将从代码角度来分析下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)


    免责声明:我们致力于保护作者版权,注重分享,被刊用文章因无法核实真实出处,未能及时与作者取得联系,或有版权异议的,请联系管理员,我们会立即处理! 部分文章是来自自研大数据AI进行生成,内容摘自(百度百科,百度知道,头条百科,中国民法典,刑法,牛津词典,新华词典,汉语词典,国家院校,科普平台)等数据,内容仅供学习参考,不准确地方联系删除处理! 图片声明:本站部分配图来自人工智能系统AI生成,觅知网授权图片,PxHere摄影无版权图库和百度,360,搜狗等多加搜索引擎自动关键词搜索配图,如有侵权的图片,请第一时间联系我们,邮箱:ciyunidc@ciyunshuju.com。本站只作为美观性配图使用,无任何非法侵犯第三方意图,一切解释权归图片著作权方,本站不承担任何责任。如有恶意碰瓷者,必当奉陪到底严惩不贷!

    目录[+]