Android5.1--PowerManagerService电源管理

2019-07-14 00:50发布

系统电源管理简介

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、Kernelpower:实现了系统电源管理框架机制。 2、Archarm(ormips or powerpc)mach-XXXpm.c:实现对特定板的处理器电源管理。 3、driverspower:是设备电源管理的基础框架,为驱动提供了电源管理接口。 图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 +")...");
                break;
            case PowerManager.GO_TO_SLEEP_REASON_LID_SWITCH:
                Slog.i(TAG, "Going to sleep due to lid switch (uid"+ uid +")...");
                break;
            case PowerManager.GO_TO_SLEEP_REASON_POWER_BUTTON:
                Slog.i(TAG, "Going to sleep due to power button (uid"+ uid +")...");
                break;
            case PowerManager.GO_TO_SLEEP_REASON_HDMI:
                Slog.i(TAG, "Going to sleep due to HDMI standby (uid"+ uid +")...");
                break;
            default:
                Slog.i(TAG, "Going to sleep by application request(uid "+ uid +")...");
                reason =PowerManager.GO_TO_SLEEP_REASON_APPLICATION;
                break;
        }
        //修改成员变量的值
        mLastSleepTime = eventTime;
        mSandmanSummoned = true;
       setWakefulnessLocked(WAKEFULNESS_DOZING, reason);//设置mWakefulness的值

        // Report the number of wake locks that will be clearedby going to sleep.
       
int numWakeLocksCleared=0;
        final int numWakeLocks= mWakeLocks.size();
        for (inti =0; i < numWakeLocks; i++) {
            final WakeLockwakeLock = mWakeLocks.get(i);
            switch (wakeLock.mFlags& PowerManager.WAKE_LOCK_LEVEL_MASK) {
                case PowerManager.FULL_WAKE_LOCK:
                case PowerManager.SCREEN_BRIGHT_WAKE_LOCK:
                case PowerManager.SCREEN_DIM_WAKE_LOCK:
                    numWakeLocksCleared+= 1;
                    break;
            }
        }
       EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED,numWakeLocksCleared);//打印Eventlog

        // Skip dozing if requested.
       
if ((flags& PowerManager.GO_TO_SLEEP_FLAG_NO_DOZE) !=0) {
           reallyGoToSleepNoUpdateLocked(eventTime, uid);
        }
    } finally {
       Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
} goToSleepNoUpdateLocked()只是发送了将要休眠的通知,然后修改了成员变量mDirty、mLastSleepTime、mWakefulness的值。更多的实际工作还是在updatePowerStateLocked()方法中完成。

三、控制系统的休眠机制

Android设备的休眠和唤醒主要基于WakeLock机制。WakeLock是一种上锁机制,只要有进程获得了WakeLock锁系统就不会进入休眠。例如,在下载文件或播放音乐时,即使休眠时间到了,系统也不能进行休眠。WakeLock可以设置超时,超时后会自动解锁。 应用使用WakeLock功能前,需要先使用new WakeLock()接口创建一个WakeLock类对象,然后调用它的acquire()方法禁止系统休眠,应用完成工作后调用release()方法来恢复休眠机制,否则系统将无法休眠,直到耗光所有电量。 WakeLock类中实现acquire()和release()方法实际上是调用了PowerManagerService的acquireWakeLock()和releaseWakeLock()方法。

1、PMS中WakeLock相关接口

acquireWakeLock()方法检查完权限后,调用了内部方法acquireWakeLockInternal()方法,如下: private void acquireWakeLockInternal(IBinder lock,intflags, String tag, String packageName,
        WorkSource ws, String historyTag,int uid, int pid) {
    synchronized (mLock) {
        if(mBlockedUids.contains(newInteger(uid)) && uid != Process.myUid()) {         WakeLock wakeLock;
        int index= findWakeLockIndexLocked(lock);//检查这个lock是否已经存在
        boolean notifyAcquire;
        if (index>= 0){//lock已经存在
            wakeLock = mWakeLocks.get(index);
            if (!wakeLock.hasSameProperties(flags,tag, ws, uid, pid)) {
                notifyWakeLockChangingLocked(wakeLock, flags, tag,packageName,
                        uid, pid, ws,historyTag);
               wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid,pid);
            }
            notifyAcquire = false;
        } else {
            wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag,uid, pid);
            try {
               lock.linkToDeath(wakeLock, 0);
            } catch (RemoteExceptionex) {
                throw new IllegalArgumentException("Wake lock is already dead.");
            }
            mWakeLocks.add(wakeLock);//将新建的WakeLock对象加入到mWakeLocks中
            notifyAcquire = true;
        }

       applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
        mDirty |= DIRTY_WAKE_LOCKS;
        updatePowerStateLocked();
        if (notifyAcquire){
             notifyWakeLockAcquiredLocked(wakeLock);
        }
    }
} acquireWakeLockInternal()方法的主要工作是创建WakeLock对象并加入到mWakeLocks列表中,这个列表中包含了所有WakeLock对象。但是如果mWakeLocks列表中已经存在具有相同token的WakeLock对象,则只更新其属性值,不会再创建对象,这个token是用户进程调用gotoSleep时传递的参数:用户进程中WakeLock对象。创建或更新WakeLock对象后,接下来调用applyWakeLockFlagsOnAcquireLocked()方法,这个方法只是调用了wakeUpNoUpdateLocked方法,如下: private boolean wakeUpNoUpdateLocked(longeventTime,intuid) {
    if (YulongFeature.FEATURE_POWERKEY_FORCE_SCREENON) {
        if (eventTime< mLastSleepTime
                || (mWakefulness ==WAKEFULNESS_AWAKE && mProximityPositive != true)
                || !mBootCompleted ||!mSystemReady) {
            return false;
       }
     } else {
               if (eventTime < mLastSleepTime || mWakefulness ==WAKEFULNESS_AWAKE
               || !mBootCompleted ||!mSystemReady) {
               return false;
            }
     }
    if (YulongFeature.FEATURE_POWERKEY_FORCE_SCREENON) {
        if (mProximityPositive==true) {
           mDisplayManagerInternal.setPowerKeyState(1);
        }
    }
 
   
Trace.traceBegin(Trace.TRACE_TAG_POWER, "wakeUp");
    try {
        switch (mWakefulness){
            case WAKEFULNESS_ASLEEP:
                Slog.i(TAG, "Waking up from sleep (uid "+ uid +")...");
                break;
            case WAKEFULNESS_DREAMING:
                Slog.i(TAG, "Waking up from dream (uid "+ uid +")...");
                break;
            case WAKEFULNESS_DOZING:
                Slog.i(TAG, "Waking up from dozing (uid "+ uid +")...");
                break;
        }

        mLastWakeTime = eventTime;
        setWakefulnessLocked(WAKEFULNESS_AWAKE,0);

        userActivityNoUpdateLocked(
                eventTime,PowerManager.USER_ACTIVITY_EVENT_OTHER, 0,uid);
    } finally {
       Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
} 在这个方法中主要是设置mLastWakeTime、mWakefulness,最后调用userActivityNoUpdateLocked方法设置mLastUserActivityTime的值。我们将acquireWakeLock()方法的流程图简单概括如下: 图3-1 acquireWakeLock流程图 我们再看下PMS的releaseWakeLock()接口,这个接口也是调用PMS的releaseWakeLockInternal()方法,如下: private void releaseWakeLockInternal(IBinder lock,intflags) {
    synchronized (mLock) {
        int index= findWakeLockIndexLocked(lock);
        if (index< 0){
            return;
        }

        if ((flags& PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) !=0){
           mRequestWaitForNegativeProximity = true;
        }

       wakeLock.mLock.unlinkToDeath(wakeLock, 0);
        removeWakeLockLocked(wakeLock,index);
    }
} releaseWakeLockInternal()方法首先查找lock在mWakeLocks中的index,然后从mWakeLocks中得到WakeLock对象,最后调用removeWakeLockLocked方法,如下: private void removeWakeLockLocked(WakeLock wakeLock,intindex) {
    mWakeLocks.remove(index);
   notifyWakeLockReleasedLocked(wakeLock);

   applyWakeLockFlagsOnReleaseLocked(wakeLock);
    mDirty |= DIRTY_WAKE_LOCKS;
    updatePowerStateLocked();
} removeWakeLockLocked方法首先从mWakeLocks中移除WakeLock对象并发出通知,接着调用applyWakeLockFlagsOnReleaseLocked(),这个方法中只是调用userActivityNoUpdateLocked()方法来把mLastUserActivityTime更新为当前时间,这样当休眠时间到时,系统就会休眠。

2、WakeLock的native层实现

我们先回到PowerManagerService的构造方法中,看看是如何创建两个变量mWakeLockSuspendBlocker和mDisplaySuspendBlocker的。 mWakeLockSuspendBlocker= createSuspendBlockerLocked("PowerManagerService.WakeLocks");
mDisplaySuspendBlocker = createSuspendBlockerLocked("PowerManagerService.Display"); 从代码中可以看出这两个变量都是调用createSuspendBlocker()方法创建的,只是参数不同,一个是PowerManagerService.WakeLocks,一个是PowerManagerService.Display;方法代码如下: private SuspendBlocker createSuspendBlockerLocked(String name) {
    SuspendBlocker suspendBlocker = new SuspendBlockerImpl(name);
    mSuspendBlockers.add(suspendBlocker);
    return suspendBlocker;
} createSuspendBlockerLocked()方法创建了一个SuspendBlockerImpl对象并返回,因此mWakeLockSuspendBlocker和mDisplaySuspendBlocker变量的类型应该是SuspendBlockerImpl。我们看下它的acquire()和release()方法,流程图如下所示。 图3-2 acruire()方法流程图 详细代码如下: public void acquire() {
    synchronized (this) {
        mReferenceCount+= 1;
        if (mReferenceCount == 1) {
           Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
           nativeAcquireSuspendBlocker(mName);
        }
    }
}

@Override
public void release() {
    synchronized (this) {
        mReferenceCount-= 1;
        if (mReferenceCount == 0) {
           nativeReleaseSuspendBlocker(mName);
           Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
        } else if (mReferenceCount <0) {
            mReferenceCount = 0;
        }
    }
} SuspendBlockerImpl类中维护了一个计数器,调用acquire()方法时计数器加1,当计数器的值为1时,调用nativeAcquireSuspendBlocker()方法。调用release()方法时计数器减1,当计数器的值为0时,调用nativeReleaseSuspendBlocked()方法。 调用的native层的函数中又分别调用了acquire_wake_lock()函数和release_wake_lock()函数,其实现如下: 从上面两个函数的实现可以看到,都是通过向不同的驱动文件中写数据来实现其功能。这里写的数据就是前面构造方法中创建变量时传递的参数“PowerManagerService.WakeLocks”和“PowerManagerService.Display”。那么acquire()和release()中使用的文件设备句柄是如何创建的呢?看下initialize_fds()函数,如下: Initialize_fds()函数先打开NEW_PATHS数组中的文件,不成功再打开OLD_PATHS数组中的设备文件。 因此,Android实现防止系统休眠的功能是通过向设备文件“sys/power/wake_lock”中写数据来完成的,如果写的是“PowerManagerService.WakeLocks”,系统将不能进入休眠状态,但是屏幕会关闭;如果写的是“PowerManagerService.Display”,则屏幕不会关闭。如果系统要恢复休眠,再向设备文件“sys/power/wake_unlock”中写入同样的字符串就OK了。

3、理解updatePowerStateLocked方法 

private void updatePowerStateLocked() {
    if (!mSystemReady|| mDirty ==0) {
        return;
    }
   Trace.traceBegin(Trace.TRACE_TAG_POWER, "updatePowerState");
    try {
        // Phase 0:更新基本状态
       
updateIsPoweredLocked(mDirty);//更新mIsPowered、mPlugType、mBatteryLevel
        updateStayOnLocked(mDirty);//更新mStayOn
       updateScreenBrightnessBoostLocked(mDirty);

        // Phase 1: 更新wakefulness
        // Loop because the wake lock anduser activity computations are influenced
        // by changes in wakefulness.
       
final long now= SystemClock.uptimeMillis();
        int dirtyPhase2= 0;
        for (;;) {
            int dirtyPhase1= mDirty;
            dirtyPhase2 |= dirtyPhase1;
            mDirty = 0;

           updateWakeLockSummaryLocked(dirtyPhase1);//更新mWakeLockSummary
           updateUserActivitySummaryLocked(now, dirtyPhase1);//更新mUserActivitySummary的值
            if (!updateWakefulnessLocked(dirtyPhase1)){//更新mWakefulness的值
                break;
            }
        }

        // Phase 2: Update display power state.更新显示设备状态;确定屏幕状态和亮度,并设置到DisplayPowerController对象中。
       
booleandisplayBecameReady= updateDisplayPowerStateLocked(dirtyPhase2);

        // Phase 3: Update dream state (depends on display readysignal).
       
updateDreamLocked(dirtyPhase2, displayBecameReady);//更新屏保状态,是否启动屏保           // Phase 4: Send notifications, if needed.发送通知
       
if(mDisplayReady){
           finishWakefulnessChangeLocked();
        }

        // Phase 5:Update suspend blocker.
        updateSuspendBlockerLocked();
    } finally {
       Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
} (1)首先调用updateIsPoweredLocked()方法,这个方法主要是通过调用BatteryService的接口来更新几个成员变量的值,如下: mIsPowered =mBatteryManagerInternal.isPowered(BatteryManager.BATTERY_PLUGGED_ANY);
mPlugType = mBatteryManagerInternal.getPlugType();
mBatteryLevel = mBatteryManagerInternal.getBatteryLevel();
mBatteryLevelLow = mBatteryManagerInternal.getBatteryLevelLow(); mIsPowered表示是否在充电,mPlugType表示充电的类型,mBatteryLevel表示当前电池电量的等级。 (2)调用updateStayOnLocked()方法来更新变量mStayOn的值,mStayOn如果为true,屏幕将保持长亮状态。在Setting中可以设置充电时屏幕长亮,如果Setting中设置了该选项,updateStayOnLocked()函数中如果检测到正在充电,会将mStayOn的值设为true。 3)接着调用updateScreenBrightnessBoostLocked()方法,这是Android5.1新增加的方法。 DIRTY_SCREEN_BRIGHTNESS_BOOST5.1新增加的,表示屏幕亮度提高的状态; (4)接下来是一个无限for循环,其实这个for循环,最多两次就结束了,后面分析。我们先来看看在循环中调用的updateWakeLockSummaryLocked()方法,这个方法的主要作用是根据PowerManagerService中所有的WakeLock对象的类型,计算一个最终的类型集合,并保存在变量mWakeLockSummary中。不管系统中一共创建了多少个WakeLock对象,一个就足以阻止系统休眠,因此,这里把所有WakeLock对象的状态总结后放到一个变量中。 应用在创建WakeLock对象时,会指定对象的类型,这个类型将作为参数传递到PowerManagerService中。WakeLock类型有: PARTIAL_WAKE_LOCK FULL_WAKE_LOCK SCREEN_BRIGHT_WAKE_LOCK SCREEN_DIM_WAKE_LOCK PROXIMITY_SCREEN_OFF_WAKE_LOCK:Android5.0新增锁,这个类型并不是用来阻止系统进入休眠,而是用来打开距离传感器控制屏幕开关的功能。如果应用持有这种类型的WakeLock,当距离传感器被遮挡时,屏幕将会关闭。 DOZE_WAKE_LOCK:Android5.0新增锁,这个类型用来让屏保管理器实现doze模式。 (5)updateUserActivitySummaryLocked()方法,这个方法根据最后一次调用userActivity()方法的时间,计算现在是否可以将表示屏幕状态的变量mUserActivitySummary的值设为SCREEN_STATE_DIMSCREEN_STATE_OFF。如果时间还没到,则发送一个定时消息MSG_USER_ACTIVITY_TIMEOUT。当处理消息的时间到了以后,会在消息的处理方法handleUserActivityTimeout()中重新调用updatePowerStateLocked()方法,再次调用updatePowerStateLocked方法时,会根据当前状态重新计算mUserActivitySummary的值。 (6)updateWakefulnessLocked()方法,这个方法是结束循环的关键。 如果它的返回值是true,表示PowerManagerService的状态发生了变化,将继续循环,然后重新调用前面的两个方法updateWakelockSummaryLocked()和updateUserActivitySummaryLocked()方法来更新状态。而第二次调用updateWakefulnessLocked方法时通常会返回false,跳出循环。 private boolean updateWakefulnessLocked(intdirty) {
    boolean changed = false;
    if ((dirty & (DIRTY_WAKE_LOCKS |DIRTY_USER_ACTIVITY | DIRTY_BOOT_COMPLETED
            | DIRTY_WAKEFULNESS |DIRTY_STAY_ON | DIRTY_PROXIMITY_POSITIVE
            | DIRTY_DOCK_STATE)) != 0) {
        if (mWakefulness == WAKEFULNESS_AWAKE &&isItBedTimeYetLocked()) {
            if (DEBUG_SPEW) {
                Slog.d(TAG, "updateWakefulnessLocked: Bedtime...");
            }
            final long time = SystemClock.uptimeMillis();
            if (shouldNapAtBedTimeLocked()) {
                changed =napNoUpdateLocked(time, Process.SYSTEM_UID);
            } else {
                changed =goToSleepNoUpdateLocked(time,
                       PowerManager.GO_TO_SLEEP_REASON_TIMEOUT, 0, Process.SYSTEM_UID);
            }
        }
    }
    return changed;
} updateWakefulnessLocked方法中首先判断dirty的值,如果是第一次调用,这个条件很容易满足。注意第二个if语句的判断条件,mWakefulness为WAKEFULNESS_AWAKE并且isItBedTimeYetLocked()方法返回true时才会执行,否则方法结束并返回false,返回false时就会跳出循环。 我们先假定调用的时候mWakefulness为WAKEFULNESS_AEAKE,下面看看isItBedTimeYetLocked方法什么情况下返回true。 private boolean isItBedTimeYetLocked() {
    return mBootCompleted &&!isBeingKeptAwakeLocked();
} private boolean isBeingKeptAwakeLocked() {
    return mStayOn
            || mProximityPositive
            || (mWakeLockSummary &WAKE_LOCK_STAY_AWAKE) != 0
           
|| (mUserActivitySummary &(USER_ACTIVITY_SCREEN_BRIGHT
                    |USER_ACTIVITY_SCREEN_DIM)) != 0
           
|| mScreenBrightnessBoostInProgress;
} 我们看下isBeingKeptAwakeLocked()方法,如果系统目前不能睡眠,这个方法返回true,这几个变量正是前面方法中设置的判断系统是否能够睡眠的变量。 因此,isItBedTimeYetLocked方法只有在系统能够进入睡眠的情况下才会返回true。 我们回到updateWakefulnessLocked方法中,假如系统能够睡眠,接下来将调用方法shouldNapAtBedTimeLocked(),这个方法将检查系统有没有设置睡眠时间到启动屏保或者插在Dock上启动屏保。如果设置了将调用napNoUpdateLocked方法,如果没有设置则调用goToSleepnoUpdateLocked方法。我们看下napNoUpdateLocked方法: private boolean napNoUpdateLocked(longeventTime,int uid) {
      if (eventTime < mLastWakeTime ||mWakefulness != WAKEFULNESS_AWAKE
            || !mBootCompleted ||!mSystemReady) {
        return false;
    }

   Trace.traceBegin(Trace.TRACE_TAG_POWER, "nap");
    try {
        mSandmanSummoned = true;
        setWakefulnessLocked(WAKEFULNESS_DREAMING,0);
    } finally {
        Trace.traceEnd(Trace.TRACE_TAG_POWER);
    }
    return true;
} private void setWakefulnessLocked(intwakefulness,int reason) {
    if (mWakefulness != wakefulness) {
        finishWakefulnessChangeLocked();

        mWakefulness = wakefulness;
        mWakefulnessChanging = true;
        mDirty |= DIRTY_WAKEFULNESS;
       mNotifier.onWakefulnessChangeStarted(wakefulness, reason);
    }
} 从上面代码中可以看到,如果if语句中4项表达式有一项为true,则返回false。但是如果是循环中第一次调用该方法,则4项正常情况下都为false,不会执行到这里。这样就会继续向下执行,就会改变mDirty和mWakefulness的值。mWakefulness的值既然改变了,当循环中第二次调用到该方法时,就会返回false,这样就结束了updatePowerStateLocked方法中的循环。 (7)结束循环后,接着调用updateDisplayPowerStateLocked()方法。这个方法的主要作用就是根据更新后的mUserActivitySummary的值来确定屏幕的状态和亮度,并设置到DisplayPowerController对象中。 (8)updateDreamLocked()方法,用来启动屏保。 (9)updateSuspendBlockerLocked()方法。来决定系统是休眠还是唤醒。

4、管理显示设备

在更新电源状态的updatePowerStateLocked()方法中,我们看到调用了updateDisplayPowerStateLocked()方法,该方法的主要作用就是更新PowerManagerService中表示显示屏状态的变量mDisplayPowerRequest,以及重新确定屏幕的亮度。注意在这个方法的结尾处调用了mDisplayPowerController的requestPowerState()方法,这个方法的返回值会赋值给mDisplayReady,如果mDisplayReadyfalse,屏幕是不会关闭的。 这里我们先看下requestPowerState()方法是怎样被调用的,流程图如下: 图3-4 显示控制流程 具体代码如下: public boolean requestPowerState(DisplayPowerRequest request,
        boolean waitForNegativeProximity) {
    synchronized (mLock) {
        boolean changed = false;
        //如果和近距离传感器相关的变量发生变化,则将change设为true
        if (waitForNegativeProximity
                &&!mPendingWaitForNegativeProximityLocked) {
           mPendingWaitForNegativeProximityLocked = true;
            changed = true;
        } //使用参数更新mPendingRequestLocked对象,如果两者不相同,则将change设为true
        if(mPendingRequestLocked ==null) {
            mPendingRequestLocked = new DisplayPowerRequest(request);
            changed = true;
        } else {
            if (!mPendingRequestLocked.equals(request)) {
               mPendingRequestLocked.copyFrom(request);
                changed = true;
            }
        }
        if(changed) {//如果chengetrue,将mDisplayReadyLocked设为false
            mDisplayReadyLocked = false;
        }

        if (changed &&!mPendingRequestChangedLocked) {
            mPendingRequestChangedLocked= true;
            sendUpdatePowerStateLocked();//发送消息
        }

        return mDisplayReadyLocked;//返回mDisplayReadyLocked
    }
} 从上面代码中可以看到,requestPowerState()方法会将参数request和waitForNegativeProximity与DisplayPowerController对象中已有的值比较,如果不同,则更新DisplayPowerController对象中的值,然后返回mDisplayReadyLocked的值,此时为false。这就意味着,如果屏幕状态发生了变化,即使这种变化是要求关闭屏幕,也不会在updateSyspendBlockerLocked()方法中立即关闭屏幕,那么这个关闭屏幕的操作在什么地方呢? 在requestPowerState()方法中最后会调用sendUpdatePowerStateLocked()方法,发送MSG_UPDATE_POWER_STATE消息,消息的处理方法是updatePowerStateLocked(),这个方法的主要作用是开始播放各种打开或关闭屏幕的动画,或者屏幕变亮或变暗的动画,之后才会将mDisplayReadyLocked设为true,这样屏幕就能关闭了。 private void updatePowerState() {
    // 。。。。。。播放动画     // Notify the power manager when ready.
   
if (ready && mustNotify) {
        // Send state change.
       
synchronized (mLock) {
            if (!mPendingRequestChangedLocked) {
                mDisplayReadyLocked = true;//mDisplayReadyLocked设为true
            }
        }
        sendOnStateChangedWithWakelock();//发送通知
    }
} updatePowerState()方法最后会调用sendOnStateChangedWithWakelock()方法来发送消息,如下: private void sendOnStateChangedWithWakelock() {
    mCallbacks.acquireSuspendBlocker();
    mHandler.post(mOnStateChangedRunnable);
}

private final Runnable mOnStateChangedRunnable = new Runnable() {
    @Override
    public void run() {
        mCallbacks.onStateChanged();
        mCallbacks.releaseSuspendBlocker();
    }
}; mCallbacks在PowerManagerService中定义了Callback方法,如下: private final DisplayManagerInternal.DisplayPowerCallbacks mDisplayPowerCallbacks =
        new DisplayManagerInternal.DisplayPowerCallbacks(){
    @Override
    public void onStateChanged() {
        synchronized (mLock) {
            mDirty |=DIRTY_ACTUAL_DISPLAY_POWER_STATE_UPDATED;
            updatePowerStateLocked();
        }
    } 在onStateChanged()方法中又调用了updatePowerStateLocked()方法,重新开始处理Power系统的状态更新。

四、电池管理服务

1、概述

Android的电池管理功能用于管理电池的充、放电功能。整个电池管理的部分包括Linux电池驱动、Android电池服务、电池属性和参数、电池曲线优化四个部分。 Linux电池驱动用户和PMIC交互、负责监听电池产生的相关事件,例如低电报警、电量发生变化、高温报警、USB插拔等。 Android电池服务,用来监听内核上报的电池事件,并将最新的电池数据上报给系统,系统收到新数据后会去更新电池显示状态、剩余电量等信息。如果收到过温报警和低电报警,系统会自动触发关机流程,保护电池和机器不受到危害。 整个电池系统的工作流程,即从底层向Framework层上报数据的流程如下:

2、电池服务

      1)、电池服务的启动和运行流程:

 2)、Android电池服务的源码结构
        Frameworkaseservicesjavacomandroidserver
        ├── SystemServer.java
                创建BatteryServices、PowerManagerService、ActivityManagerService
        ├── BatterySevices.java
                监听底层上报的battery事件,广播电池发生改变的消息 Frameworkaseservicesjavacomandroidserveram
        ├── ActivityManagerService.java
                创建BatteryStatsService
        ├── BatteryStatsService.java
                统计和记录电池参数的信息 Frameworkaseservicesjavacomandroidserverpower
        ├── PowerManagerService.java
                监听电池发生变化的广播消息,并调节系统的电源状态,例如亮屏 Frameworkasecorejavacominternalos
        ├── BatteryStatsImpl.java
                统计和记录电池参数的信息,并通知其他模块 Systemcorehealthd
        ├── healthd.cpp
                创建uevent socket,监听内核上报的内核事件
        ├── BatteryMonitor.cpp
                初始化本地电池数据结构,将power_supply路径下属性节点路径填充进去,
        ├── BatteryMonitor.h
        ├── BatteryPropertiesRegistrar.cpp
                创建电池属性监听器,并将其注册到Android的系统服务中
        ├── BatteryPropertiesRegistrar.h

3、BatteryService类的作用

在PowerManagerService中调用了BatteryService类的一些接口来获得电池的状态,下面来看看BatteryService是如何获得电池状态数据的。 public BatteryService(Context context) {
    super(context);
    mBatteryStats =BatteryStatsService.getService();//获得BatteryStatsService对象 //读取系统设定的各种低电量报警值
  
// 监听设备文件:无效的充电设备
   
if(newFile("/sys/devices/virtual/switch/invalid_charger/state").exists()) {
       mInvalidChargerObserver.startObserving(
                "DEVPATH=/devices/virtual/switch/invalid_charger");
    }
} publicvoid onStart() {
    IBinder b =ServiceManager.getService("batteryproperties");
    final IBatteryPropertiesRegistrarbatteryPropertiesRegistrar =
           IBatteryPropertiesRegistrar.Stub.asInterface(b);
    try {
       batteryPropertiesRegistrar.registerListener(newBatteryListener());
    } catch (RemoteException e) {
        // Should never happen.
   
} 1、BatteryService的构造方法首先获得BatteryStatsService的对象,BatteryStatsService主要的功能是收集系统中各个模块和进程的耗电情况。通过BatteryStatsService记录的数据,可以找到耗电量大的模块然后进行分析加以改进。 2、接下来读取了系统设定的各种低电量报警值,如下: l  mCriticalBatteryLevel:表示电量严重不足时的值,低于这个值系统将关闭; l  mLowBatteryWarningLevel:表示电量不足时的值,低于这个值系统将发出警告; l  mLowBatteryCloseWarningLevel:表示停止电量不足警告