PowerManagerService电源管理和Wacklock锁申请与释放机制

来源:互联网 发布:淘宝上丰胸霜可信吗 编辑:程序博客网 时间:2024/06/06 07:03

一. 电源管理概述

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

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

二. 电源管理架构

    Android的电源管理主要是通过wacklock和定时器来切换系统的状态,使系统的功耗降至最低,整个系统的框架可以分为四个层次:

    应用接口层(PowerManager.java),Framework层(PowerManagerService.java),HAL层(Power.c),和内核层(kernel/Power)。

应用层:PowerManager中开放给应用一系列接口,应用可以调用PM的接口申请wakelock,唤醒系统,使系统进入睡眠等操作

架层:应用调用PowerManager开放的接口,来对系统进行一些列的操作是在PowerManagerService中完成的,PowerManagerService计算系统中和Power相关的计算,是整个电源管理的决策系统。同时协调Power如何与系统其它模块的交互,比如亮屏,暗屏,系统睡眠,唤醒等等。

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

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

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

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

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

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


1. PowerManagerService

    /frameworks/base/services/java/com/android/server/power/PowerManagerService.java
    PowerManagerService是Android电源管理的核心服务,主要功能是控制系统的待机状态,控制显示屏的开关和亮度调节,以及查询和控制光线传感器和距离传感器等

1.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()。


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。

控制系统的休眠机制

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()方法。来决定系统是休眠还是唤醒。




1.Wakelock 锁机制:
应用程序可以通过申请 wakelock 锁的机制来对系统是否待机作出投票,当有任何一个应用申请了 wakelock 锁,待机时没有释放掉,系统是不会进入待机的,直到所有应用的 wakelock 锁都释放掉了,才会进入待机。

2.Wakelock 锁的用法:

    /**
     * 获取电源锁,保持该服务在屏幕熄灭时仍然获取CPU时,保持运行
     */ 
    private void acquireWakeLock() { 
        if (null == wakeLock) { 
            PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); 
            wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK  | PowerManager.ON_AFTER_RELEASE, 

            getClass()  .getCanonicalName()); 
            if (null != wakeLock) { 
                Log.i(TAG, "call acquireWakeLock"); 
                wakeLock.acquire(); 
            } 
        } 
    } 

 private WakeLock wakeLock = null;

// 释放设备电源锁  
    private void releaseWakeLock() { 
        if (null != wakeLock && wakeLock.isHeld()) { 
            Log.i(TAG, "call releaseWakeLock"); 
            wakeLock.release(); 
            wakeLock = null; 
        } 
    }

WakeLock 类型以及说明:

    PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。
    SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯
    SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,允许保持屏幕高亮显示,允许关闭键盘灯
    FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度
    ACQUIRE_CAUSES_WAKEUP:强制使屏幕亮起,这种锁主要针对一些必须通知用户的操作.
    ON_AFTER_RELEASE:当锁被释放时,保持屏幕亮起一段时间


最后 AndroidManifest.xml 声明权限:
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
    <uses-permission android:name="android.permission.DEVICE_POWER"/>

在 onResume() 或者 onStart() 中申请 wakelock 锁,即调用acquireWakeLock()方法,来保证系统不会进入待机

在 onPause() 或者 onDistroy() 中处理应用待机后再释放掉 wakelock 锁,此时调用releaseWakeLock()方法

另外WakeLock的设置是 Activiy 级别的,不是针对整个Application应用的。如果有多个activity一定需要注意下!

3.Wakelock 锁的用法:

adb shell cat /sys/kernel/debug/wakeup_sources

adb shell dumpsys power

http://www.th7.cn/Program/Android/201507/516607.shtml

2 0
原创粉丝点击