一、初始化信息
首先看看Android中的几种电源状态定义,这几个值定义了不同的led开闭状态以及lcd背光的不同亮度模式:
// flags for setPowerState private static final int SCREEN_ON_BIT = 0x00000001; private static final int SCREEN_BRIGHT_BIT = 0x00000002; private static final int BUTTON_BRIGHT_BIT = 0x00000004; private static final int KEYBOARD_BRIGHT_BIT = 0x00000008; private static final int BATTERY_LOW_BIT = 0x00000010; // values for setPowerState // SCREEN_OFF == everything off private static final int SCREEN_OFF = 0x00000000; // SCREEN_DIM == screen on, screen backlight dim private static final int SCREEN_DIM = SCREEN_ON_BIT; // SCREEN_BRIGHT == screen on, screen backlight bright private static final int SCREEN_BRIGHT = SCREEN_ON_BIT | SCREEN_BRIGHT_BIT; // SCREEN_BUTTON_BRIGHT == screen on, screen and button backlights bright private static final int SCREEN_BUTTON_BRIGHT = SCREEN_BRIGHT | BUTTON_BRIGHT_BIT; // SCREEN_BUTTON_BRIGHT == screen on, screen, button and keyboard backlights bright private static final int ALL_BRIGHT = SCREEN_BUTTON_BRIGHT | KEYBOARD_BRIGHT_BIT; // used for noChangeLights in setPowerState() private static final int LIGHTS_MASK = SCREEN_BRIGHT_BIT | BUTTON_BRIGHT_BIT | KEYBOARD_BRIGHT_BIT;
在frameworks/base/core/res/res/values/config.xml中配置自动背光的总开关mUseSoftwareAutoBrightness以及自动背光模式下的背光数值,如果没有lightsensor用于自动背光调整,则需要将mUseSoftwareAutoBrightness配置为false,配置项如下:
<bool name="config_automatic_brightness_available">true</bool> <!-- Array of light sensor LUX values to define our levels for auto backlight brightness support. The N entries of this array define N + 1 zones as follows: Zone 0: 0 <= LUX < array[0] Zone 1: array[0] <= LUX < array[1] ... Zone N: array[N - 1] <= LUX < array[N] Zone N + 1: array[N] <= LUX < infinity Must be overridden in platform specific overlays --> <integer-array name="config_autoBrightnessLevels"> <item>3</item> <item>10</item> <item>40</item> <item>65</item> <item>145</item> <item>300</item> <item>550</item> <item>930</item> <item>1250</item> </integer-array> <!-- Array of output values for LCD backlight corresponding to the LUX values in the config_autoBrightnessLevels array. This array should have size one greater than the size of the config_autoBrightnessLevels array. This must be overridden in platform specific overlays --> <integer-array name="config_autoBrightnessLcdBacklightValues"> <item>101</item> <item>117</item> <item>142</item> <item>183</item> <item>195</item> <item>216</item> <item>234</item> <item>245</item> <item>250</item> <item>250</item> </integer-array> <!-- Array of output values for button backlight corresponding to the LUX values in the config_autoBrightnessLevels array. This array should have size one greater than the size of the config_autoBrightnessLevels array. This must be overridden in platform specific overlays --> <integer-array name="config_autoBrightnessButtonBacklightValues"> <item>255</item> <item>255</item> <item>255</item> <item>0</item> <item>0</item> <item>0</item> <item>0</item> <item>0</item> <item>0</item> <item>0</item> </integer-array> <!-- Array of output values for keyboard backlight corresponding to the LUX values in the config_autoBrightnessLevels array. This array should have size one greater than the size of the config_autoBrightnessLevels array. This must be overridden in platform specific overlays --> <integer-array name="config_autoBrightnessKeyboardBacklightValues"> </integer-array>
在初始化的时候会调用如下代码获取配置信息:
// 获取系统默认配置 Resources resources = mContext.getResources(); // 屏幕动画是否开启 mAnimateScreenLights = resources.getBoolean( com.android.internal.R.bool.config_animateScreenLights); mUnplugTurnsOnScreen = resources.getBoolean( com.android.internal.R.bool.config_unplugTurnsOnScreen); // 软件自动背光调整是否打开 mUseSoftwareAutoBrightness = resources.getBoolean( com.android.internal.R.bool.config_automatic_brightness_available); // 读取自动背光参考值 if (mUseSoftwareAutoBrightness) { mAutoBrightnessLevels = resources.getIntArray( com.android.internal.R.array.config_autoBrightnessLevels); mLcdBacklightValues = resources.getIntArray( // lcd背光值 com.android.internal.R.array.config_autoBrightnessLcdBacklightValues); mButtonBacklightValues = resources.getIntArray( // button背光值 com.android.internal.R.array.config_autoBrightnessButtonBacklightValues); mKeyboardBacklightValues = resources.getIntArray( // keyboard背光值 com.android.internal.R.array.config_autoBrightnessKeyboardBacklightValues); mLightSensorWarmupTime = resources.getInteger( com.android.internal.R.integer.config_lightSensorWarmupTime); }
二、代码流程分析
在Android中,如果framework层接收到输入事件就会调用PowerManagerService里面的userActivity()去设置系统的下一个电源状态,流程图如下:
当调用userActivity()之后,将进行一些事件类型和状态的判断并先后调用setPowerState()设置新的状态、setTimeoutLocked()设置新状态超时后的状态,代码分析如下:
private void userActivity(long time, long timeoutOverride, boolean noChangeLights, int eventType, boolean force) { // 检测是否忽略CHEEK_EVENT事件 if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0) && (eventType == CHEEK_EVENT)) { if (false) { Slog.d(TAG, "dropping cheek event mPokey=0x" + Integer.toHexString(mPokey)); } return; } // 检测是否忽略CHEEK_EVENT与TOUCH事件 if (((mPokey & POKE_LOCK_IGNORE_TOUCH_AND_CHEEK_EVENTS) != 0) && (eventType == TOUCH_EVENT || eventType == TOUCH_UP_EVENT || eventType == LONG_TOUCH_EVENT || eventType == CHEEK_EVENT)) { if (false) { Slog.d(TAG, "dropping touch mPokey=0x" + Integer.toHexString(mPokey)); } return; } if (false) { if (((mPokey & POKE_LOCK_IGNORE_CHEEK_EVENTS) != 0)) { Slog.d(TAG, "userActivity !!!");//, new RuntimeException()); } else { Slog.d(TAG, "mPokey=0x" + Integer.toHexString(mPokey)); } } synchronized (mLocks) { if (mSpew) { Slog.d(TAG, "userActivity mLastEventTime=" + mLastEventTime + " time=" + time + " mUserActivityAllowed=" + mUserActivityAllowed + " mUserState=0x" + Integer.toHexString(mUserState) + " mWakeLockState=0x" + Integer.toHexString(mWakeLockState) + " mProximitySensorActive=" + mProximitySensorActive + " timeoutOverride=" + timeoutOverride + " force=" + force + " eventType=" + eventType); } // 如果当前屏幕为关闭状态则不处理 if (isScreenTurningOffLocked()) { Slog.d(TAG, "ignoring user activity while turning off screen"); return; } // 如果正在等待距离传感器为负值时用户按下power键则关闭距离传感器功能 if (mProximitySensorActive && mProximityWakeLockCount == 0) { mProximitySensorActive = false; } if (mLastEventTime <= time || force) { // 判断事件是否为最新的 mLastEventTime = time; if ((mUserActivityAllowed && !mProximitySensorActive) || force) { // 在用户点击触摸屏或者虚拟按键并且不是自动背光状态时设置下一个状态为全亮 if ((eventType == BUTTON_EVENT || eventType == TOUCH_EVENT || eventType == TOUCH_UP_EVENT || eventType == LONG_TOUCH_EVENT) && (!mUseSoftwareAutoBrightness || !mAutoBrightessEnabled)) { mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT); } else { // 设置系统下一个状态为SCREEN_BRIGHT,并保留上次状态 mUserState |= SCREEN_BRIGHT; } int uid = Binder.getCallingUid(); long ident = Binder.clearCallingIdentity(); try { mBatteryStats.noteUserActivity(uid, eventType); } catch (RemoteException e) { // Ignore } finally { Binder.restoreCallingIdentity(ident); } // 获取当前WakeLock状态 mWakeLockState = mLocks.reactivateScreenLocksLocked(); // 设置下一个状态 setPowerState(mUserState | mWakeLockState, noChangeLights, WindowManagerPolicy.OFF_BECAUSE_OF_USER); // 设置超时后的状态 setTimeoutLocked(time, timeoutOverride, SCREEN_BRIGHT); } } } if (mPolicy != null) { mPolicy.userActivity(); } }
private void setTimeoutLocked(long now, final long originalTimeoutOverride, int nextState) { long timeoutOverride = originalTimeoutOverride; // 超时时间 if (mBootCompleted) { // 判断系统是否启动完成 synchronized (mLocks) { long when = 0; if (timeoutOverride <= 0) { switch (nextState) { case SCREEN_BRIGHT: when = now + mKeylightDelay; // 关闭按键灯的时间 break; case SCREEN_DIM: if (mDimDelay >= 0) { when = now + mDimDelay; // 屏幕亮度降低的时间 break; } else { Slog.w(TAG, "mDimDelay=" + mDimDelay + " while trying to dim"); } case SCREEN_OFF: synchronized (mLocks) { when = now + mScreenOffDelay; // 关闭屏幕时间 } break; default: when = now; break; } } else { // 如果指定了originalTimeoutOverride override: { if (timeoutOverride <= mScreenOffDelay) { when = now + timeoutOverride; nextState = SCREEN_OFF; break override; } timeoutOverride -= mScreenOffDelay; if (mDimDelay >= 0) { if (timeoutOverride <= mDimDelay) { when = now + timeoutOverride; nextState = SCREEN_DIM; break override; } timeoutOverride -= mDimDelay; } when = now + timeoutOverride; nextState = SCREEN_BRIGHT; } } if (mSpew) { Slog.d(TAG, "setTimeoutLocked now=" + now + " timeoutOverride=" + timeoutOverride + " nextState=" + nextState + " when=" + when); } mHandler.removeCallbacks(mTimeoutTask); // 清除超时任务 mTimeoutTask.nextState = nextState; // 设置超时后的状态 mTimeoutTask.remainingTimeoutOverride = timeoutOverride > 0 ? (originalTimeoutOverride - timeoutOverride) : -1; mHandler.postAtTime(mTimeoutTask, when); // 启动超时任务 mNextTimeout = when; // for debugging } } }
private class TimeoutTask implements Runnable { int nextState; // access should be synchronized on mLocks long remainingTimeoutOverride; public void run() { synchronized (mLocks) { if (mSpew) { Slog.d(TAG, "user activity timeout timed out nextState=" + this.nextState); } if (nextState == -1) { return; } mUserState = this.nextState; // 设置全局变量 setPowerState(this.nextState | mWakeLockState); // 设置电源状态 long now = SystemClock.uptimeMillis(); switch (this.nextState) // 设置超时后的下一个状态 { case SCREEN_BRIGHT: // 如果当前屏幕全亮则下一状态为暗屏 if (mDimDelay >= 0) { setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_DIM); break; } case SCREEN_DIM: // 如果当前屏幕为暗屏则下一状态为熄屏 setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_OFF); break; } } } }
在setPowerState()中如果leds有变化则调用updateLightsLocked()更新leds的状态,如果lcd新状态和当前状态不同,则可能需要调用setScreenStateLocked()处理系统的休眠和唤醒流程,代码分析如下:
private void setPowerState(int newState, boolean noChangeLights, int reason) { synchronized (mLocks) { int err; if (mSpew) { Slog.d(TAG, "setPowerState: mPowerState=0x" + Integer.toHexString(mPowerState) + " newState=0x" + Integer.toHexString(newState) + " noChangeLights=" + noChangeLights + " reason=" + reason); } if (noChangeLights) { // 如果不改变light状态,则保持上次light状态 newState = (newState & ~LIGHTS_MASK) | (mPowerState & LIGHTS_MASK); } if (mProximitySensorActive) { // 如果距离传感器锁定则关闭lcd背光 // don't turn on the screen when the proximity sensor lock is held newState = (newState & ~SCREEN_BRIGHT); } if (batteryIsLow()) { // 如果当前低电则添加低电状态 newState |= BATTERY_LOW_BIT; } else { newState &= ~BATTERY_LOW_BIT; } if (newState == mPowerState) { // 如果本次状态和上次状态一致则直接返回 return; } // 如果正在启动并且没有设置自动背光则为全亮 if (!mBootCompleted && !mUseSoftwareAutoBrightness) { newState |= ALL_BRIGHT; } boolean oldScreenOn = (mPowerState & SCREEN_ON_BIT) != 0; // 当前屏幕状态 boolean newScreenOn = (newState & SCREEN_ON_BIT) != 0; // 下次屏幕状态 if (mSpew) { Slog.d(TAG, "setPowerState: mPowerState=" + mPowerState + " newState=" + newState + " noChangeLights=" + noChangeLights); Slog.d(TAG, " oldKeyboardBright=" + ((mPowerState & KEYBOARD_BRIGHT_BIT) != 0) + " newKeyboardBright=" + ((newState & KEYBOARD_BRIGHT_BIT) != 0)); Slog.d(TAG, " oldScreenBright=" + ((mPowerState & SCREEN_BRIGHT_BIT) != 0) + " newScreenBright=" + ((newState & SCREEN_BRIGHT_BIT) != 0)); Slog.d(TAG, " oldButtonBright=" + ((mPowerState & BUTTON_BRIGHT_BIT) != 0) + " newButtonBright=" + ((newState & BUTTON_BRIGHT_BIT) != 0)); Slog.d(TAG, " oldScreenOn=" + oldScreenOn + " newScreenOn=" + newScreenOn); Slog.d(TAG, " oldBatteryLow=" + ((mPowerState & BATTERY_LOW_BIT) != 0) + " newBatteryLow=" + ((newState & BATTERY_LOW_BIT) != 0)); } if (mPowerState != newState) { // 判断状态是否改变 updateLightsLocked(newState, 0); // 更新按键灯状态 mPowerState = (mPowerState & ~LIGHTS_MASK) | (newState & LIGHTS_MASK); } if (oldScreenOn != newScreenOn) { // 判断屏幕状态是否不同 if (newScreenOn) { // 如果要点亮屏幕 // When the user presses the power button, we need to always send out the // notification that it's going to sleep so the keyguard goes on. But // we can't do that until the screen fades out, so we don't show the keyguard // too early. if (mStillNeedSleepNotification) { sendNotificationLocked(false, WindowManagerPolicy.OFF_BECAUSE_OF_USER); } // Turn on the screen UNLESS there was a prior // preventScreenOn(true) request. (Note that the lifetime // of a single preventScreenOn() request is limited to 5 // seconds to prevent a buggy app from disabling the // screen forever; see forceReenableScreen().) boolean reallyTurnScreenOn = true; if (mSpew) { Slog.d(TAG, "- turning screen on... mPreventScreenOn = " + mPreventScreenOn); } if (mPreventScreenOn) { // 是否阻止屏幕点亮 if (mSpew) { Slog.d(TAG, "- PREVENTING screen from really turning on!"); } reallyTurnScreenOn = false; } if (reallyTurnScreenOn) { err = setScreenStateLocked(true); // 唤醒系统,点亮屏幕 long identity = Binder.clearCallingIdentity(); try { mBatteryStats.noteScreenBrightness(getPreferredBrightness()); mBatteryStats.noteScreenOn(); } catch (RemoteException e) { Slog.w(TAG, "RemoteException calling noteScreenOn on BatteryStatsService", e); } finally { Binder.restoreCallingIdentity(identity); } } else { setScreenStateLocked(false); // 休眠系统 // But continue as if we really did turn the screen on... err = 0; } mLastTouchDown = 0; mTotalTouchDownTime = 0; mTouchCycles = 0; EventLog.writeEvent(EventLogTags.POWER_SCREEN_STATE, 1, reason, mTotalTouchDownTime, mTouchCycles); if (err == 0) { mPowerState |= SCREEN_ON_BIT; sendNotificationLocked(true, -1); } } else { // 如果要关闭屏幕 // cancel light sensor task mHandler.removeCallbacks(mAutoBrightnessTask); // 取消背光自动调整任务 mScreenOffTime = SystemClock.elapsedRealtime(); // 获取关闭时间 long identity = Binder.clearCallingIdentity(); try { mBatteryStats.noteScreenOff(); } catch (RemoteException e) { Slog.w(TAG, "RemoteException calling noteScreenOff on BatteryStatsService", e); } finally { Binder.restoreCallingIdentity(identity); } mPowerState &= ~SCREEN_ON_BIT; // 设置状态位 mScreenOffReason = reason; if (!mScreenBrightness.animating) { // 判断是否打开关屏动画 err = screenOffFinishedAnimatingLocked(reason); } else { err = 0; mLastTouchDown = 0; } } } updateNativePowerStateLocked(); // 更新HAL层状态 } }在updateLightsLocked()里面将会进行一系列的状态处理, 比如调用applyButtonState()获取button led的相关数据和状态,然后调用setLightBrightness()设置leds,代码分析如下:
private void updateLightsLocked(int newState, int forceState) { final int oldState = mPowerState; if ((newState & SCREEN_ON_BIT) != 0) { // 如果屏幕打开则设置按键灯 newState = applyButtonState(newState); // 请求button灯状态 newState = applyKeyboardState(newState); // 请求keyboard灯状态 } final int realDifference = (newState ^ oldState); // 判断状态是否相同,取得不同的位 final int difference = realDifference | forceState; // 是否强制更新状态 if (difference == 0) { return; } int offMask = 0; int dimMask = 0; int onMask = 0; int preferredBrightness = getPreferredBrightness(); // 获取参考亮度 if ((difference & KEYBOARD_BRIGHT_BIT) != 0) { // 如果keyboard有变化 if ((newState & KEYBOARD_BRIGHT_BIT) == 0) { offMask |= KEYBOARD_BRIGHT_BIT; } else { onMask |= KEYBOARD_BRIGHT_BIT; } } if ((difference & BUTTON_BRIGHT_BIT) != 0) { // 如果button有变化 if ((newState & BUTTON_BRIGHT_BIT) == 0) { offMask |= BUTTON_BRIGHT_BIT; } else { onMask |= BUTTON_BRIGHT_BIT; } } // 如果状态不同且forceState有效或者屏幕状态变化 if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) { int nominalCurrentValue = -1; // If there was an actual difference in the light state, then // figure out the "ideal" current value based on the previous // state. Otherwise, this is a change due to the brightness // override, so we want to animate from whatever the current // value is. // 如果屏幕状态变化 if ((realDifference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) { switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) { // 判断当前屏幕状态 case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT: // 屏幕全亮状态 nominalCurrentValue = preferredBrightness; break; case SCREEN_ON_BIT: // 屏幕DIM状态 nominalCurrentValue = Power.BRIGHTNESS_DIM; break; case 0: // 屏幕关闭状态 nominalCurrentValue = Power.BRIGHTNESS_OFF; break; case SCREEN_BRIGHT_BIT: default: // not possible nominalCurrentValue = (int)mScreenBrightness.curValue; break; } } int brightness = preferredBrightness; int steps = ANIM_STEPS; // 动画步数 if ((newState & SCREEN_BRIGHT_BIT) == 0) { // 下一个状态为DIM或者OFF // dim or turn off backlight, depending on if the screen is on // the scale is because the brightness ramp isn't linear and this biases // it so the later parts take longer. final float scale = 1.5f; // 每次变化比例 float ratio = (((float)Power.BRIGHTNESS_DIM)/preferredBrightness); if (ratio > 1.0f) ratio = 1.0f; if ((newState & SCREEN_ON_BIT) == 0) { // 下一个状态为OFF if ((oldState & SCREEN_BRIGHT_BIT) != 0) { // was bright steps = ANIM_STEPS; } else { // was dim steps = (int)(ANIM_STEPS*ratio*scale); } brightness = Power.BRIGHTNESS_OFF; // 设置brightness } else { // 下一个状态为DIM if ((oldState & SCREEN_ON_BIT) != 0) { // was bright steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale); } else { // was dim steps = (int)(ANIM_STEPS*ratio); } if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) { // If the "stay on while plugged in" option is // turned on, then the screen will often not // automatically turn off while plugged in. To // still have a sense of when it is inactive, we // will then count going dim as turning off. mScreenOffTime = SystemClock.elapsedRealtime(); } brightness = Power.BRIGHTNESS_DIM; } } long identity = Binder.clearCallingIdentity(); try { mBatteryStats.noteScreenBrightness(brightness); } catch (RemoteException e) { // Nothing interesting to do. } finally { Binder.restoreCallingIdentity(identity); } mScreenBrightness.setTargetLocked(brightness, steps, // 设置背光亮度 INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); } if (mSpew) { Slog.d(TAG, "offMask=0x" + Integer.toHexString(offMask) + " dimMask=0x" + Integer.toHexString(dimMask) + " onMask=0x" + Integer.toHexString(onMask) + " difference=0x" + Integer.toHexString(difference) + " realDifference=0x" + Integer.toHexString(realDifference) + " forceState=0x" + Integer.toHexString(forceState) ); } if (offMask != 0) { // 如果有灯要关闭 if (mSpew) Slog.i(TAG, "Setting brightess off: " + offMask); setLightBrightness(offMask, Power.BRIGHTNESS_OFF); } if (dimMask != 0) { int brightness = Power.BRIGHTNESS_DIM; if ((newState & BATTERY_LOW_BIT) != 0 && brightness > Power.BRIGHTNESS_LOW_BATTERY) { brightness = Power.BRIGHTNESS_LOW_BATTERY; } if (mSpew) Slog.i(TAG, "Setting brightess dim " + brightness + ": " + dimMask); setLightBrightness(dimMask, brightness); // 设置leds } if (onMask != 0) { // 如果有灯要打开 int brightness = getPreferredBrightness(); // 获取亮度值,包括按键灯的亮度值,都是从用户设置中获取 if ((newState & BATTERY_LOW_BIT) != 0 && brightness > Power.BRIGHTNESS_LOW_BATTERY) { brightness = Power.BRIGHTNESS_LOW_BATTERY; } if (mSpew) Slog.i(TAG, "Setting brightess on " + brightness + ": " + onMask); setLightBrightness(onMask, brightness); // 设置leds } }
private int applyButtonState(int state) { int brightness = -1; if ((state & BATTERY_LOW_BIT) != 0) { // 如果电池电量低则不覆盖亮度值 return state; } if (mButtonBrightnessOverride >= 0) { // 判断亮度值是否有效 brightness = mButtonBrightnessOverride; } else if (mLightSensorButtonBrightness >= 0 && mUseSoftwareAutoBrightness) { // 根据lightsensor设置亮度值 // 这里有android系统的一个bug,如果开启自动背光后再关闭自动背光 // 会导致mLightSensorButtonBrightness为之前自动背光时的值,如果为0按键灯就不会再被点亮了 brightness = mLightSensorButtonBrightness; } if (brightness > 0) { return state | BUTTON_BRIGHT_BIT; // 如果亮度值大于0则返回状态 } else if (brightness == 0) { return state & ~BUTTON_BRIGHT_BIT; } else { return state; } }
在setLightBrightness()中将根据标志依次调用JNI接口去设置leds,代码分析如下:
private void setLightBrightness(int mask, int value) { int brightnessMode = (mAutoBrightessEnabled ? LightsService.BRIGHTNESS_MODE_SENSOR : LightsService.BRIGHTNESS_MODE_USER); // 设置背光模式 if ((mask & SCREEN_BRIGHT_BIT) != 0) { mLcdLight.setBrightness(value, brightnessMode); // 调用JNI接口设置lcd亮度 } if ((mask & BUTTON_BRIGHT_BIT) != 0) { mButtonLight.setBrightness(value); // 调用JNI接口设置button灯 } if ((mask & KEYBOARD_BRIGHT_BIT) != 0) { mKeyboardLight.setBrightness(value); // 调用JNI接口设置keyboard灯 } }