android power--wakelock framework


在开始前,先看一个图,这是android power的架构图:


wakelock是一种阻止系统进入睡眠等低功耗模式的机制,Android改动较大的另一处是增加了wakelock机制。实现在wakelock.c和userwakelock.c中。wakelock可以阻止处于正常运行(active)或者空闲(idle)状态的系统进入睡眠等低功耗状态。直到所持有的wakelock全部被释放,系统才能进入睡眠等低功耗的状态。

我们接下来看一看wake lock的机制是怎么运行和起作用的,主要关注 wakelock.c(wake_lock)文件就可以了。

    1) wake lock 有加锁和解锁两种状态,加锁的方式有两种:
    • 第一种是永久的锁住,这样的锁除非显示的放开,是不会解锁的,所以这种锁的使用是非常小心的。
    • 第二种是超时锁,这种锁会锁定系统唤醒一段时间,如果这个时间过去了,这个锁会自动解除。

    2) 锁有两种类型:
    • WAKE_LOCK_SUSPEND:这种锁会防止系统进入睡眠(suspend)。
    • WAKE_LOCK_IDLE:这种锁不会影响系统的休眠,用于阻止系统在持有锁的过程中进入低功耗状态。即直到wake_lock被释放,系统才会从idle状态进入低功耗状态,此低功耗状态将使中断延迟或禁用一组中断。

    内核维护了:
    a).两个链表,active_wake_locks[WAKE_LOCK_TYPE_COUNT]
    active_wake_locks[0]维护的是suspend lock.
    active_wake_locks[1]维护的是idle lock.
    b).一个链表,inactive_locks来记录所有处于inactive状态的锁.
    如果申请了partial wakelock,那么即使按Power键,系统也不会进Sleep,如Music播放时 如果申请了其它的wakelocks,按Power键,系统还是会进Sleep

    3) 在wake lock中, 会有3个地方让系统直接开始suspend(), 分别是:
    • 在wake_unlock()中, 如果发现解锁以后没有任何其他的wake lock了,就开始休眠
    • 在定时器都到时间以后,定时器的回调函数会查看是否有其他的wake lock,如果没有,就在这里让系统进入睡眠。
    • 在wake_lock() 中,对一个wake lock加锁以后,会再次检查一下有没有锁, 我想这里的检查是没有必要的, 更好的方法是使加锁的这个操作原子化,而不是繁冗的检查,而且这样的检查也有可能漏掉。


    下面讲述wakelock是如何上层申请到传到kernel里面的:


    首先应用服务在获取申请wakelock权限需要在对应服务文件夹下面的AndroidManifest.xml 里面加上以下一句话:

<uses-permission android:name="android.permission.WAKE_LOCK" />
    Android 提供了现成 android.os.PowerManager 类 ,类中提供 newWakeLock(int flags, String tag)方法来取得相应层次的锁, 此函数的定义frameworks/base/core/java/android/os/PowerManager.java

    public WakeLock newWakeLock(int levelAndFlags, String tag) {
        validateWakeLockParameters(levelAndFlags, tag);
        return new WakeLock(levelAndFlags, tag, mContext.getOpPackageName());
    }

    应用程序在申请wakelock时就会调用到上面这个函数,例如:

            mWakeLock = ((PowerManager)mContext.getSystemService(Context.POWER_SERVICE)).
                                       newWakeLock( PowerManager.PARTIAL_WAKE_LOCK, TAG );//PARTIAL_WAKE_LOCK是wakelock的类型,具体有以下几种类型PARTIAL_WAKE_LOCK:保持CPU 运转,屏幕和键盘灯有可能是关闭的。 
//SCREEN_DIM_WAKE_LOCK:保持CPU 运转,允许保持屏幕显示但有可能是灰的,允许关闭键盘灯 
//SCREEN_BRIGHT_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,允许关闭键盘灯
//FULL_WAKE_LOCK:保持CPU 运转,保持屏幕高亮显示,键盘灯也保持亮度 
//ACQUIRE_CAUSES_WAKEUP:不会唤醒设备,强制屏幕马上高亮显示,键盘灯开启。有一个例外,如果有notification弹出的话,会唤醒设备。 
//ON_AFTER_RELEASE:WakeLock 被释放后,维持屏幕亮度一小段时间,减少WakeLock 循环时的闪烁情况
//如果申请了partial wakelock,那么即使按Power键,系统也不会进Sleep,如Music播放时 如果申请了其它的wakelocks,按Power键,系统还是会进Sleep

            mWakeLock.acquire();//申请锁这个里面会调用PowerManagerService里面acquireWakeLock()
…………
            mWakeLock.release();//释放锁,显示的释放,如果申请的锁不在此释放系统就不会进入休眠<pre name="code" class="cpp">这个里面会调用PowerManagerService里面releaseWakeLock。

 

  先说mWakeLock.acquire()或者acquire(timeout),这里会调用到PowerManager.java里面的acquire()(永久锁)或者acquire(long timeout)(超时锁):

        public void acquire() {
            synchronized (mToken) {
                acquireLocked();
            }
        }

        public void acquire(long timeout) {
            synchronized (mToken) {
                acquireLocked();
                mHandler.postDelayed(mReleaser, timeout);
            }
        }
这里都会调用到acquireLocked()函数:
        private void acquireLocked() {
            if (!mRefCounted || mCount++ == 0) {
                mHandler.removeCallbacks(mReleaser);
                Trace.asyncTraceBegin(Trace.TRACE_TAG_POWER, mTraceName, 0);
                try {
                    mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
                            mHistoryTag);
                } catch (RemoteException e) {
                }
                mHeld = true;
            }
        }
mWakeLock.release()则会调用到PowerManager.java里面的release():

public void release() {
            release(0);
        }

public void release(int flags) {
            synchronized (mToken) {
                if (!mRefCounted || --mCount == 0) {
                    mHandler.removeCallbacks(mReleaser);
                    if (mHeld) {
                        Trace.asyncTraceEnd(Trace.TRACE_TAG_POWER, mTraceName, 0);
                        try {
                            mService.releaseWakeLock(mToken, flags);
                        } catch (RemoteException e) {
                        }
                        mHeld = false;
                    }
                }
                if (mCount < 0) {
                    throw new RuntimeException("WakeLock under-locked " + mTag);
                }
            }
        }

这里会继续往下调用获取锁会调用mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,mHistoryTag),释放锁则会调用public void releaseWakeLock(IBinder lock, int flags) ,这里的mService是一个IPowerManager接口类,PowerManager的实现通过IPowerManager来调用Power服务的接口,IPowerManager实现了acquireWakeLock, releaseWakeLock, shutd

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值