Android5.1--PowerManagerService电源管理

本文详细介绍了Android系统的电源管理,重点讲解了PowerManagerService如何控制系统的待机状态,包括用户活动报告、系统休眠机制以及电池管理服务。PowerManagerService通过WakeLock控制休眠,监测用户活动来调整休眠计时,并通过电池服务获取电池状态,确保电源的有效管理。
摘要由CSDN通过智能技术生成

系统电源管理简介

Android电源管理概述

电源管理(PowerManager)在任何设备中都是最重要的组成部分之一,良好的电源管理方案可以达到节能、延长电池寿命、降低辐射、降温等目的。

移动设备的电量主要有两种元件消耗:CPU和显示屏。设法降低这两种元件的耗电量就是电源管理的关键。为移动设备设计的CPU大都有两种工作频率,为了省电,大部分时间CPU都工作在较低的频率下,只有进行密集计算时,如视频解码,才会切换到高频状态。而显示屏省电的方法是尽量减少亮屏的时间,但是显示屏的开关和应用有很大的关系,因此,系统需要有一套机制来控制显示屏的开关和亮度,这是电源管理模块的主要工作之一。

Android电源管理组织架构

Android的电源管理主要是通过锁和定时器来切换系统的状态,使系统的功耗降至最低,整个系统的框架可以分为四个层次,分别是应用程序层、Framework层、硬件抽象层(HAL)和内核层。Android电源管理框架如图1-1所示。

l  应用层:这里所谓的应用层主要是指应用程序和其他使用电源管理的Service,包括但不限于以下Services: PowerManagerService、BatteryService、LightService等。

l  框架层:在Android框架层包含了对应用层接口的API调用以及电源的协调工作,主要包含PowerManager.java、PowerManagerService.java、com_android_server_PowerManagerService.cpp、Power.java、android_os_Power.cpp。其中PowerManagerService.java是核心,Power.java提供底层的函数接口,与JNI层进行交互。PowerManager.java是提供给应用层调用的。android_os_power.cpp是jni交互文件。这一层的功能相对比较复杂,比如系统状态的切换,背光的调节及开关,Wake Lock的申请和释放等等,但这一层跟硬件平台无关。

l  HAL层:该层只有一个Power.c文件,该文件通过sysfs的方式与kernel进行通信。主要功能有申请wake_lock,释放wake_lock,设置屏幕状态等。用户空间的native库绝不能直接调用Android电源管理(见下图)。绕过Android运行时的电源管理政策,将破坏该系统。所有对电源管理的调用应通过Android的PowerManagerAPI来完成。

l  Kernel层:内核层的电源管理方案实现主要包含三部分:

1、Kernel\power\:实现了系统电源管理框架机制。

2、Arch\arm(ormips or powerpc)\mach-XXX\pm.c:实现对特定板的处理器电源管理。

3、drivers\power:是设备电源管理的基础框架,为驱动提供了电源管理接口。

图1-1 Android电源管理框架图

系统正常开机后,Brightness的亮度会设置成用户设定的亮度,系统Screen off timer开始计时,在计时时间到之前,如果有任何的userActivity事件发生,比如Touch click等事件,则将重新设置screen off timer,系统保持在Awake状态。如果应用程序在这段时间申请了Full wakelock,系统也将保持在Awake状态。在没有交互的情况下,首先进入到Awake状态,之后进入Dozing状态,最后进入Asleep状态。

电源管理服务--PowerManagerService

PowerManagerService是Android电源管理的核心服务,主要功能是控制系统的待机状态,控制显示屏的开关和亮度调节,以及查询和控制光线传感器和距离传感器等。PowerManagerService的启动流程如下图2-1所示。


图2-1PowerManagerService启动流程

初始化过程

PowerManagerService也是在SystemServer中创建并加入到ServiceManager中的,代码如下:

mPowerManagerService = mSystemServiceManager.startService(
PowerManagerService.class);

    调用SystemServiceManager的startService方法创建PowerManagerService对象并注册到ServiceManager中。PowerManagerService的构造方法代码如下:

public PowerManagerService(Context context) {
    super(context);
    mContext = context;
//创建处理消息的线程和Handler对象
    mHandlerThread = new ServiceThread(TAG,
           Process.THREAD_PRIORITY_DISPLAY, false/*allowIo*/);
    mHandlerThread.start();
    mHandler = new PowerManagerHandler(mHandlerThread.getLooper());

    synchronized (mLock) {
        mWakeLockSuspendBlocker =createSuspendBlockerLocked("PowerManagerService.WakeLocks");
        mDisplaySuspendBlocker =createSuspendBlockerLocked("PowerManagerService.Display");
        mDisplaySuspendBlocker.acquire();
        mHoldingDisplaySuspendBlocker = true;
        mHalAutoSuspendModeEnabled = false;
        mHalInteractiveModeEnabled = true;

        mWakefulness = WAKEFULNESS_AWAKE;//设置PowerManagerService的状态

        nativeInit();
        nativeSetAutoSuspend(false);
        nativeSetInteractive(true);
    }
}

         PowerManagerService的构造方法中首先创建了处理消息的线程和发送消息的PowerManagerHandler对象,接着创建了mWakeLockSuspendBlocker对象、mDisplaySuspendBlocker对象。

         变量mWakefulness的值被设置成WAKEFULNESS_AWAKE,它用来标示PowerManagerService的状态,一共有四种定义:

l  WAKEFULNESS_ASLEEP:表示系统当前处于休眠状态,只能被wakeUp()调用唤醒。

l  WAKEFULNESS_AWAKE:表示系统目前处于正常运行状态。

l  WAKEFULNESS_DREAMING:表示系统当前正处于播放屏保的状态。

l  WAKEFULNESS_DOZING:表示系统正处于“doze”状态。这种状态下只有低耗电的“屏保”可以运行,其他应用进程都被挂起。

最后,构造方法调用了nativeInit()方法,主要工作就是装载”Power”模块,之后调用模块的初始化函数init()。

系统准备工作—SystemReady方法

SystemServer创建PowerManagerService后,还会调用它的SystemReady()方法,相当于在系统准备就绪后对PowerManagerService再进行一些初始化工作。SystemReady()方法代码如下:

public void systemReady(IAppOpsService appOps) {
    synchronized (mLock) {
        mSystemReady = true;
        mAppOps = appOps;
        mDreamManager =getLocalService(DreamManagerInternal.class);//获取DreamManagerService对象
        mDisplayManagerInternal =getLocalService(DisplayManagerInternal.class);//DisplayManagerService
        mPolicy = getLocalService(WindowManagerPolicy.class);//WindowManagerPolicy
        mBatteryManagerInternal =getLocalService(BatteryManagerInternal.class);//BatteryService

//获取最小、最大、默认屏幕亮度
        。。。。。。
//创建SensorManager对象,用于和SensorService交互
        SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());

        mBatteryStats = BatteryStatsService.getService();//获得BatteryStatsService的引用对象
        mNotifier = new Notifier(Looper.getMainLooper(), mContext, mBatteryStats,
                mAppOps,createSuspendBlockerLocked("PowerManagerService.Broadcasts"),
                mPolicy);//创建Notifier对象

        mWirelessChargerDetector = new WirelessChargerDetector(sensorManager,
               createSuspendBlockerLocked("PowerManagerService.WirelessChargerDetector"),
                mHandler);//创建检测无线充电的对象WirelessChargerDetector
        mSettingsObserver = new SettingsObserver(mHandler);//创建监听系统设置项变化的对象

        mLightsManager = getLocalService(LightsManager.class);//LightsManager对象
        mAttentionLight =mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);

        //初始化Power的管理模块
        mDisplayManagerInternal.initPowerManagement(
                mDisplayPowerCallbacks,mHandler, sensorManager);

        。。。。。。 //注册广播接收器
        。。。。。。//注册监听更多的settngs项的变化
        // Go.
        readConfigurationLocked();
        updateSettingsLocked();
        mDirty |= DIRTY_BATTERY_STATE;
        updatePowerStateLocked();
    }
}

       systemReady()方法中通过调用getLocalService()方法得到一些在SystemServer中运行的内部服务的对象。在systemservice中也创建了一些内部使用的服务,这些服务没有通过ServiceManager发布,而是通过内部的LocalService类来管理。这些内部服务的共同特征是从SystemService类派生,通过getLocalService()方法可以获得参数关联的内部服务对象。

systemReady()方法完成的主要工作如下:

l  获取最小、最大、默认3种屏幕亮度。

l  创建SystemSensorManager对象,用于和SensorService交互。

l  创建Notifer对象。用于广播系统中和Power相关的变化。

l  创建WirelessChargerDetector对象,用于无线充电检测的传感器。

l  调用DisplayManagerService的initPowerManagement()方法来初始化Power管理模块。

l  注册Observer监听系统设置的变化。

l  监听其他模块广播的Intent。PowerManagerService需要关注系统的变化,这里注册了很多系统广播的接收器。包括系统启动完成、“屏保”启动和关闭、用户切换、Dock插拔等。

报告用户活动—userActivity接口

PowerManager是PowerManagerService的代理类,它提供了一些接口让用户进程可以和PowerManagerService交互,下面分析一些接口来进一步了解PowerManagerService的工作。

userActivity()接口用于用户进程向PowerManagerService报告用户影响系统休眠的活动。例如,用户点击屏幕时,系统会调用该方法来告诉PowerManagerService用户点击的时间,这样PowerManagerService将更新内部保存的时间值,从而推迟系统休眠的时间。userActivity()方法主要通过调用内部的userActivityInternal()方法来完成工作,userActivity流程图如图2-2所示:

图2-2 userActivity流程图

具体代码如下:

   private void userActivityInternal(long eventTime, int event, int flags, int uid) {
    synchronized (mLock) {
        if (userActivityNoUpdateLocked(eventTime, event, flags, uid)) {
            updatePowerStateLocked();
        }
    }
}

userActivityInternal()先调用了userActivityNoUpdateLocked()方法,然后再调用updatePowerStateLocked()方法。userActivityNoUpdateLocked()方法只是把参数保存到内部变量中,并不会采取任何动作,而PowerManagerService中核心的方法是updatePowerStateLocked()。我们先看下userActivityNoUpdateLocked()方法:

private boolean userActivityNoUpdateLocked(longeventTime,intevent,intflags,intuid) {
    if (eventTime< mLastSleepTime || eventTime < mLastWakeTime
            || !mBootCompleted ||!mSystemReady) {
        return false;
    }

   Trace.traceBegin(Trace.TRACE_TAG_POWER, "userActivity");
    try {
        if (eventTime> mLastInteractivePowerHintTime) {
           powerHintInternal(POWER_HINT_INTERACTION, 0);//powerHintInternal是通过JNI调用底层函数,将cpu频率提高等等
            mLastInteractivePowerHintTime= eventTime;//记录时间
        }

        mNotifier.onUserActivity(event,uid);//发出通知

        if (mWakefulness== WAKEFULNESS_ASLEEP
                || mWakefulness ==WAKEFULNESS_DOZING
                || (flags &PowerManager.USER_ACTIVITY_FLAG_INDIRECT) != 0) {
            return false;
        }//如果系统处于休眠或doze模式,返回

        if ((flags& PowerManager.USER_ACTIVITY_FLAG_NO_CHANGE_LIGHTS) !=0){
            if (eventTime> mLastUserActivityTimeNoChangeLights
                    && eventTime> mLastUserActivityTime) {
               mLastUserActivityTimeNoChangeLights = eventTime;//记录时间
                mDirty |=DIRTY_USER_ACTIVITY;
                return true;
            }
        } else {
            if (eventTime> mLastUserActivityTime) {
                mLastUserActivityTime =eventTime;//记录时间
                mDirty |=DIRTY_USER_ACTIVITY;
                return true;
            }
        }
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return false;
}

       userActivityNoUpdateLocked()方法主要的工作是更新几个内部变量。其中mLastUserActivityTime变量和mLastUserActivityTimeNoChangeLights变量用来记录调用userActivity()方法的时间,mDirty用来记录用户的操作类型,这些变量的值在updatePowerStateLocked()方法中将会作为是否要执行 睡眠或唤醒操作的依据。

强制系统进入休眠模式—gotoSleep接口

gotoSleep()接口用来强制系统进入休眠模式。通常当系统一段时间无人操作后,系统将调用gotoSleep()接口来进入休眠模式。大体流程如下:

图2-3 gotoSleep流程

PowerManagerService的gotoSleep()接口主要是调用内部方法goToSleepInternal()来完成其功能。如下:

private void goToSleepInternal(longeventTime,intreason,int flags,intuid) {
    synchronized (mLock) {
        if (goToSleepNoUpdateLocked(eventTime,reason, flags, uid)) {
            updatePowerStateLocked();
        }
    }
}

goToSleepInternal()代码的结构和前面的userActivity类似,都是先调用一个内部方法,然后再调用updatePowerStateLocked()方法,我们先看下goToSleepNoUpdateLocked()方法,如下:

private boolean goToSleepNoUpdateLocked(longeventTime,intreason,intflags,intuid) {
    try {
        switch (reason){
            case PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN:
                Slog.i(TAG, "Going to sleep due to deviceadministration policy "
                       
+ "(uid "+ uid +")...");
                break;
            case PowerManager.GO_TO_SLEEP_REASON_TIMEOUT:
                Slog.i(TAG, "Going to sleep due to screen timeout(uid "+ uid +

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值