该系列文章总纲链接:专题分纲目录 Android Framework 电源子系统


本章关键点总结 & 说明:

Android Framework 电源子系统(02)系统休眠 wakelock机制_ide

本章节主要关注➕ 系统休眠 wakeLock 部分 即可。该章节 主要是 对wakelock机制中acquire和release的实现流程分析,其中native部分的一些实现是在PMS中进行说明的。


android系统的休眠唤醒主要是 使用了WakeLock锁,WakeLock是一种上锁机制。只要有应用拿着这个锁,CPU就无法进入休眠状态,一直处于工作状态。比如,手机屏幕在屏幕关闭的时候,有些应用依然可以唤醒屏幕提示用户消息,这里就是用到了wakelock锁机制,虽然手机屏幕关闭了,但是这些应用依然在运行着。当持有WakeLock锁时,系统就无法睡眠,同时WakeLock锁可以设置超时,超时后会自动解锁。

1 wakeLock锁使用简介

一个普通应用使用wakelock的方式如下所示:

WakeLock wakeLock = null;

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

//释放设备电源锁
private void releaseWakeLock()
{
    if (null != wakeLock)
    {
        wakeLock.release();
        wakeLock = null;
    }
}

首先是通过getSystemService获取pm代理,之后使用pm的newWakeLock方法创建一个新的wakelock锁对象,当执行wakelock的require方法时,就保持应用一直运行;当执行release方法时,就释放掉该锁。


2 获取WakeLock接口{require和release接口说明}

pm代理类的require和release接口实现如下:

//acquire 2个接口实现
public void acquire() {
    synchronized (mToken) {
        acquireLocked();
    }
}

public void acquire(long timeout) {
    synchronized (mToken) {
        acquireLocked();
        mHandler.postDelayed(mReleaser, timeout);
    }
}

//release 2个接口实现
public void release() {
    release(0);
}

public void release(int flags) {
    synchronized (mToken) {
        if (!mRefCounted || --mCount == 0) {
            mHandler.removeCallbacks(mReleaser);
            if (mHeld) {
                try {
                    mService.releaseWakeLock(mToken, flags);
                } catch (RemoteException e) {
                }
                mHeld = false;
            }
        }
        //...
    }
}

这里的acquire接口均调用了acquireLocked方法,实现如下:

private void acquireLocked() {
    if (!mRefCounted || mCount++ == 0) {
        mHandler.removeCallbacks(mReleaser);
        try {
            mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
                    mHistoryTag);
        } catch (RemoteException e) {
        }
        mHeld = true;
    }
}

综上,pm代理类的require和release接口最终调用了PMS的acquireWakeLock和releaseWakeLock方法;相关代码实现如下:

@Override // Binder call
public void acquireWakeLock(IBinder lock, int flags, String tag, String packageName,
        WorkSource ws, String historyTag) {
    //...
    PowerManager.validateWakeLockParameters(flags, tag);

    //...权限处理相关
    try {
        acquireWakeLockInternal(lock, flags, tag, packageName, ws, historyTag, uid, pid);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}

@Override // Binder call
public void releaseWakeLock(IBinder lock, int flags) {
    //...
    final long ident = Binder.clearCallingIdentity();
    try {
        releaseWakeLockInternal(lock, flags);
    } finally {
        Binder.restoreCallingIdentity(ident);
    }
}

这里分别调用了PMS的acquireWakeLockInternal和releaseWakeLockInternal方法,这里开始分开解读

@1 acquireWakeLockInternal分析

代码实现如下:

private void acquireWakeLockInternal(IBinder lock, int flags, String tag, String packageName,
        WorkSource ws, String historyTag, int uid, int pid) {
    synchronized (mLock) {
        WakeLock wakeLock;
        //检查lock是否存在
        int index = findWakeLockIndexLocked(lock);
        boolean notifyAcquire;
        if (index >= 0) {//lock已经存在
            wakeLock = mWakeLocks.get(index);
            if (!wakeLock.hasSameProperties(flags, tag, ws, uid, pid)) {
                // Update existing wake lock.  This shouldn't happen but is harmless.
                notifyWakeLockChangingLocked(wakeLock, flags, tag, packageName,
                        uid, pid, ws, historyTag);
                wakeLock.updateProperties(flags, tag, packageName, ws, historyTag, uid, pid);
            }
            notifyAcquire = false;
        } else {//创建新的wakelock
            wakeLock = new WakeLock(lock, flags, tag, packageName, ws, historyTag, uid, pid);
            try {
                lock.linkToDeath(wakeLock, 0);
            } catch (RemoteException ex) {
                throw new IllegalArgumentException("Wake lock is already dead.");
            }
            //将新的wakeLock加入到mWakeLocks中
            //注意:该列表包含了系统中所有的wakeLock
            mWakeLocks.add(wakeLock);
            notifyAcquire = true;
        }

        applyWakeLockFlagsOnAcquireLocked(wakeLock, uid);
        mDirty |= DIRTY_WAKE_LOCKS;
        updatePowerStateLocked();
        if (notifyAcquire) {
            notifyWakeLockAcquiredLocked(wakeLock);
        }
    }
}

继续分析applyWakeLockFlagsOnAcquireLocked,代码实现如下:

private void applyWakeLockFlagsOnAcquireLocked(WakeLock wakeLock, int uid) {
    if ((wakeLock.mFlags & PowerManager.ACQUIRE_CAUSES_WAKEUP) != 0
            && isScreenLock(wakeLock)) {
        wakeUpNoUpdateLocked(SystemClock.uptimeMillis(), uid);
    }
}

这里继续分析wakeUpNoUpdateLocked,代码实现如下:

private boolean wakeUpNoUpdateLocked(long eventTime, int uid) {
    if (eventTime < mLastSleepTime || mWakefulness == WAKEFULNESS_AWAKE
            || !mBootCompleted || !mSystemReady) {
        return false;
    }

    try {
        //...
        mLastWakeTime = eventTime;
        /*更新成员变量
            mLastUserActivityTimeNoChangeLights
            mLastUserActivityTime
            mDirty
        */
        setWakefulnessLocked(WAKEFULNESS_AWAKE, 0);
        //更新成员变量mLastUserActivityTime的值
        userActivityNoUpdateLocked(
                eventTime, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, uid);
    } finally {
        //...
    }
    return true;
}

@2 releaseWakeLockInternal分析

代码实现如下:

private void releaseWakeLockInternal(IBinder lock, int flags) {
    synchronized (mLock) {
        //检查lock是否存在
        int index = findWakeLockIndexLocked(lock);
        if (index < 0) {
            return;
        }
        //通过索引获取对应的wakeLock
        WakeLock wakeLock = mWakeLocks.get(index);
        if ((flags & PowerManager.RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY) != 0) {
            mRequestWaitForNegativeProximity = true;
        }

        wakeLock.mLock.unlinkToDeath(wakeLock, 0);
        //将其从链表mWakeLocks中移除
        removeWakeLockLocked(wakeLock, index);
    }
}

这里继续分析removeWakeLockLocked,代码实现如下:

private void removeWakeLockLocked(WakeLock wakeLock, int index) {
    mWakeLocks.remove(index);
    notifyWakeLockReleasedLocked(wakeLock);
    applyWakeLockFlagsOnReleaseLocked(wakeLock);
    mDirty |= DIRTY_WAKE_LOCKS;
    updatePowerStateLocked();
}

这里一共做了这样几件事情:

  1. 将传递进来的wakelock从链表mWakeLocks中移除并发出通知。
  2. 更新成员变量mLastUserActivityTime的值为当前时间,休眠时间到,系统会自动休眠。
  3. 调用关键方法updatePowerStateLocked()。

3 WakeLock native层实现

见上一节 createSuspendBlockerLocked分析 部分 SuspendBlockerImpl的acquire方法和release方法的实现。实际上在 PowerManagerService中 创建了两个wakeLock,分别是 PowerManagerService.WakeLocks 和 PowerManagerService.Display

特殊说明:

Android防止系统休眠的方式是通过向设备节点"/sys/power/wake_lock"写入数据

  1. 如果写的是PowerManagerService.WakeLocks,系统将不能休眠,但屏幕会关闭
  2. 如果写的是PowerManagerService.Display,系统将不能休眠,同时屏幕也不会关闭

如果系统要恢复休眠,则向"/sys/power/wake_unlock"写入同样的字符串就可以了。