PowerManagerService学习笔记

平台:Android4.0
场景:PMS是framework中相对简单明了的service,学习老邓第二本android书籍。
时间:2012.8.8

以下大部分内容摘抄于老邓第二本android书籍。

1.在PMS的init()函数中,将创建两个HandlerThread对象。一个为mScreenOffThread,用于调节关闭屏幕时的亮度的渐变过程。另一个为PMS的主要工作线程——mHandlerThread,在其调用的initInThread()函数中,做了一些重要的初始化操作:注册要监听的广播,读取一些配置参数,设置一个监听对象,以及为后面将要发出的screenOn广播准备好intent,创建处于锁保护状态下的UnsynchronizedWakeLock等。

       mScreenOffThread = new HandlerThread("PowerManagerService.mScreenOffThread") {
            @Override
            protected void onLooperPrepared() {
                mScreenOffHandler = new Handler();
                synchronized (mScreenOffThread) {
                    mInitComplete = true;
                    mScreenOffThread.notifyAll();
                }
            }
        };
        mScreenOffThread.start();

        synchronized (mScreenOffThread) {
            while (!mInitComplete) {
                try {
                    mScreenOffThread.wait();
                } catch (InterruptedException e) {
                    // Ignore
                }
            }
        }

android中常用的的处理方式:线程A中创建了线程B,然后线程A等待线程B的创建完成再继续执行。

2.initInThread()中几个读取的参数解析:
mAnimateScreenLights:bool——关闭屏幕时屏幕光是否渐暗,默认为true。
mUnplugTurnsOnScreen:bool——拔掉USB线,是否点亮屏幕,默认为false。
mScreenBrightnessDim:int——PMS可设置的屏幕亮度的最小值,默认为20。
mUseSoftwareAutoBrightness:bool——是否启用Setting中的亮度自动调节,如果硬件不支持该功能,将由软件控制。默认为false。

3.使用PM的WakeLock申请wakelock锁的时候,使用的flag的对应的意义:
flag值 Cpu Screen Keyboard 备注
PARTIAL_WAKE_LOCK on off off 不受电源键影响
SCREEN_DIM_WAKE_LOCK on dim off 按下电源键后,系统进入休眠
SCREEN_BRIGHT_WAKE_LOCK on bright off 按下电源键后,系统进入休眠
FULL_WAKE_LOCK on bright on 按下电源键后,系统进入休眠
ACQUIRE_CAUSES_WAKEUP 正常情况下,获取wakelock并不会唤醒机器。加上此标志后,可以唤醒机器(点亮屏幕等)。此flag对PARTIAL_WAKE_LOCK无效。
ON_AFTER_RELEASE 当wakelock释放后,如没有该标志,系统会立即黑屏。设置了该标志,系统将延迟一段时间再黑屏。

4.PM中的acquire()函数实则将调用到PMS中的acquireWakeLockLocked()函数。同时在PMS中,也存在一个内部类WakeLock类,主要作为PM中WakeLock的客户端,通过binder监听着服务端死亡的消息,做出release的异常处理。(即防止acquire后死亡的进程导致的没有release)。

5.PMS的acquireWakeLockLocked()函数在处理完isScreenLock(flags)(除了PARTIAL_WAKE_LOCK之外的flag都将进入这个分支,即与屏幕相关的wakelock)的最后将调用setPowerState(),此为PMS中比较重要的一个函数。主要用来真实控制各个与电力使用相关的设备的开关操作。关于SetPowerState()函数,需要注意以下几点:
(1).setScreenStateLocked()函数—将调用到Power.setScreenStateLocked(),此函数将通过jni调用到下层进行屏幕灯开关操作。
(2).updateLightsLocked()函数—此函数用来控制键盘灯或者按键灯的状态。
(3).mPreventScreenOn变量。其相关到preventScreenOn()函数,此函数的作用在于,提供一个接口给应用程序,使得应用程序可以阻止屏幕点亮。(为了防止activity切换导致的闪屏现象)在preventScreenOn()函数中,做了一定的超时处理,默认是5秒钟后mPreventScreenOn变量将会被重新置为false。
(4).sendNotificationLocked()函数,用于发送Screen_ON和Screen_OFF广播。为了防止快速按下power按键引起的广播和屏幕亮灭之间的快速切换,在其中使用了mBroadcastQueue这个长度为3的int数组。至于if (index == 1 && !on)为什么就表示screenOff的原因?

6.在PMS的acquireWakeLockLocked()的最后:

        else if ((flags & LOCK_MASK) == PowerManager.PARTIAL_WAKE_LOCK) {
            if (newlock) {
                mPartialCount++;
                if (mPartialCount == 1) {
                    if (LOG_PARTIAL_WL) EventLog.writeEvent(EventLogTags.POWER_PARTIAL_WAKE_STATE, 1, tag);
                }
            }
            Power.acquireWakeLock(Power.PARTIAL_WAKE_LOCK,PARTIAL_NAME);
        }

此处即解释了为什么PARTIAL_WAKE_LOCK不受power按键的影响。可简单理解为,其他的几个flag为框架层的wakelock,再按下power按键的时候,将会把他们都无效掉。而PARTIAL_WAKE_LOCK是通过Power.acquireWakeLock(),真实申请了kernel层的wakelock。

7.updateNativePowerStateLocked()函数的作用—将当前屏幕状态的信息保存在JNI层,其重要相关的两个变量为:gScreenOn和gScreenBright。

8.PMS中的userAcitivty(),其对外的接口封装在PM中的userActivity()。应用程序都可以使用它。其主要是重新计算了WakeLock的状态,设置了mUserState的值,再调用setPowerState()来设置相应的改变。最后还有两个重要的调用:
(1).setTimeoutLocked()—重新开始屏幕计时。通过mTimeoutTask的使用,进行屏幕状态的相应的改变设置。
(2).mPolicy.userActivity()—PhoneWindowManger.java中的userActivity()函数,主要用于对mScreenLockTimeout的控制,即出现屏幕锁的控制。

9.关于Power按键的处理:当power被按下,从input系统上来到框架以后,在4.0上会先进入到com_android_server_InputManager.cpp中的interceptKeyBeforeQueueing()函数,其先会调用

 wmActions = env->CallIntMethod(mCallbacksObj, gCallbacksClassInfo.interceptKeyBeforeQueueing, keyEventObj, policyFlags, isScreenOn);

即调用到了PhoneWindowManager.java中去了,并返回一个int型。然后调用handleInterceptActions()函数—此函数将根据返回的wmActions的值,来确定是否需要通过JNI来调用PMS中的goToSleep()函数。因此,此处解释了,为什么长按power按键会弹出关机对话框,而短按power按键会关闭屏幕。(因为PhoneWindowManager.java中处理了power长按的情况,并返回了一个使得handleInterceptActions()函数不会调用goToSleep()函数的返回值)
短按power的情况,PMS中的goToSleep()最终将调用到其goToSleepLocked()。

            for (int i=0; i<N; i++) {
                WakeLock wl = mLocks.get(i);
                if (isScreenLock(wl.flags)) {
                    if (((wl.flags & LOCK_MASK) == PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)
                            && reason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR) {
                        proxLock = true;
                    } else {
                        mLocks.get(i).activated = false;
                        numCleared++;
                    }
                }
            }
            if (!proxLock) {
                mProxIgnoredBecauseScreenTurnedOff = true;
                if (mDebugProximitySensor) {
                    Slog.d(TAG, "setting mProxIgnoredBecauseScreenTurnedOff");
                }
            }
            EventLog.writeEvent(EventLogTags.POWER_SLEEP_REQUESTED, numCleared);
            mStillNeedSleepNotification = true;
            mUserState = SCREEN_OFF;
            setPowerState(SCREEN_OFF, false, reason);

这里刚好解释了我之前的判断,框架层与屏幕相关的wakelock在此处被false掉,因此power按键将使得其无效。同时mWakeLockState和mUserState都被置为SCREEN_OFF,并调用setPowerState(SCREEN_OFF, false, reason)使得屏幕熄灭。

你可能感兴趣的:(PowerManagerService学习笔记)