Android系统中的屏幕状态切换以及亮度设置

Android系统的状态包括wake、earlysuspend以及suspend状态,其使用锁和定时器来进行状态的切换。
而在wake状态,屏幕首先是调至设定的亮度,如果没有其他动作,当经过一段时间后屏幕会变暗,再经过一段时间屏幕会关闭,于是屏幕的状态也包括3种:bright、dim、off。
在Android应用框架层中的PowerManagerService.java(framework/base/services/java/com/android/server/)中实现了上述屏幕状态的切换。下面对PowerManagerService.java如何切换屏幕状态进行分析。

在PowerManagerService的初始化函数init中,会进行必要参数的初始化,包括LightsService,BatteryService,Thread等等,然后会使用forceUserActivityLocked点亮屏幕。
[java]  view plain  copy
  1. void init(Context context, LightsService lights, IActivityManager activity,  
  2.             BatteryService battery) {  
  3.     mLightsService = lights;  // LightsService mLightsService  
  4.     mContext = context;  
  5.     mActivityService = activity;  
  6.     mBatteryStats = BatteryStatsService.getService();  
  7.     mBatteryService = battery;  
  8.     mLcdLight = lights.getLight(LightsService.LIGHT_ID_BACKLIGHT);  // LightsService.Light mLcdLight  
  9.     mButtonLight = lights.getLight(LightsService.LIGHT_ID_BUTTONS);  
  10.     mKeyboardLight = lights.getLight(LightsService.LIGHT_ID_KEYBOARD);  
  11.     mAttentionLight = lights.getLight(LightsService.LIGHT_ID_ATTENTION);  
  12.     ......  
  13.     synchronized (mLocks) {  
  14.         updateNativePowerStateLocked();  
  15.         forceUserActivityLocked(); // 强制点亮屏幕  
  16.         mInitialized = true;  
  17.     }  
  18. }  

在forceUserActivityLocked中主要是使用userActivity点亮屏幕
[java]  view plain  copy
  1. private void forceUserActivityLocked() {  
  2.     if (isScreenTurningOffLocked()) {  
  3.         // cancel animation so userActivity will succeed  
  4.         mScreenBrightness.animating = false;  
  5.     }  
  6.     boolean savedActivityAllowed = mUserActivityAllowed;  
  7.     mUserActivityAllowed = true;  
  8.     userActivity(SystemClock.uptimeMillis(), false);  // 使用userActivity点亮屏幕  
  9.     mUserActivityAllowed = savedActivityAllowed;  
  10. }  
  11.   
  12. public void userActivity(long time, boolean noChangeLights) {  
  13.     ......  
  14.     userActivity(time, -1, noChangeLights, OTHER_EVENT, false);  
  15. }  

在userActivity方法中会收集所有锁的状态(mLocks存储了所有申请的锁),然后通过setPowerState方法来设置系统的状态,最后通过setTimeoutLocked来开启定时器
[java]  view plain  copy
  1. private void userActivity(long time, long timeoutOverride, boolean noChangeLights,  
  2.         int eventType, boolean force) {  
  3.     ......  
  4.     if (!mAutoBrightnessButtonKeyboard) {  
  5.         // Turn on button (and keyboard) backlights on any event, so that they  
  6.         // don't suddenly disappear when the lock screen is unlocked (OTHER_EVENT),  
  7.         // and so capacitive buttons can be found on devices where they lack  
  8.         // identifying surface features.  
  9.         mUserState = (mKeyboardVisible ? ALL_BRIGHT : SCREEN_BUTTON_BRIGHT);  
  10.     } else {  
  11.         // don't clear button/keyboard backlights when the screen is touched.  
  12.         mUserState |= SCREEN_BRIGHT;  
  13.     }  
  14.     mWakeLockState = mLocks.reactivateScreenLocksLocked();  
  15.     setPowerState(mUserState | mWakeLockState, noChangeLights, WindowManagerPolicy.OFF_BECAUSE_OF_USER);  
  16.     setTimeoutLocked(time, timeoutOverride, SCREEN_BRIGHT);  
  17.     ......  
  18. }  

setPowerState方法会根据输入的状态调用setScreenStateLocked方法来设置系统状态
[java]  view plain  copy
  1. private void setPowerState(int newState, boolean noChangeLights, int reason)  
  2. {  
  3.     ......  
  4.     boolean oldScreenOn = (mPowerState & SCREEN_ON_BIT) != 0// 记录系统当前屏幕状态  
  5.     boolean newScreenOn = (newState & SCREEN_ON_BIT) != 0// 记录新的屏幕状态  
  6.     final boolean stateChanged = mPowerState != newState; // 记录状态是否改变  
  7.     if (oldScreenOn != newScreenOn) { // 新的屏幕状态和当前屏幕状态不一致时  
  8. if (newScreenOn) { // 新状态是开启屏幕  
  9.    boolean reallyTurnScreenOn = true;  
  10.    if (mPreventScreenOn) {  
  11.                 reallyTurnScreenOn = false// 如果屏幕开启被阻止,则设置reallyTurnScreenOn为false  
  12.             }  
  13.    if (reallyTurnScreenOn) {  
  14.                 err = setScreenStateLocked(true); // 使用setScreenStateLocked唤醒系统  
  15. ......  
  16.             } else {  
  17.                 setScreenStateLocked(false); // 使系统睡眠  
  18.                 // But continue as if we really did turn the screen on...  
  19.                 err = 0;  
  20.             }  
  21.    if (err == 0) {  
  22.             sendNotificationLocked(true, -1);  
  23.             if (stateChanged) {  
  24.                 updateLightsLocked(newState, 0);  
  25.             }  
  26.             mPowerState |= SCREEN_ON_BIT;  
  27. else { // 如果新状态是关闭屏幕,则使用screenOffFinishedAnimatingLocked方法使系统睡眠  
  28.    if (stateChanged) {  
  29.                 updateLightsLocked(newState, 0);  
  30.             }  
  31.    ......  
  32.    if (!mScreenBrightness.animating) {  
  33.                 err = screenOffFinishedAnimatingLocked(reason); // 该方法也是调用setScreenStateLocked方法睡眠系统  
  34.             } else {  
  35.                 err = 0;  
  36.                 mLastTouchDown = 0;  
  37.             }  
  38. }  
  39.     } else if (stateChanged) {  
  40.         // Screen on/off didn't change, but lights may have.  
  41.         updateLightsLocked(newState, 0);  
  42.     }  
  43.     ......  
  44. }  

在setScreenStateLocked方法中会使用Power.setScreenState方法调用jni层中的函数,最终会传递至内核层,在内核层中执行相应的睡眠系统或唤醒系统
[java]  view plain  copy
  1. private int setScreenStateLocked(boolean on) {  
  2.     ......  
  3.     int err = Power.setScreenState(on);  
  4.     ......  
  5. }  

而setScreenStateLocked方法中,函数updateLightsLocked用来更新lights,后面将进行分析。

以上一小段介绍了userActivity唤醒系统的简单流程,而在PowerManagerService的初始化函数中,不仅会通过userActivity中的setPowerState来唤醒系统,同时也会使用userActivity中的setTimeoutLocked来开启一个定时器,用于切换屏幕的状态
[java]  view plain  copy
  1. private void setTimeoutLocked(long now, final long originalTimeoutOverride, int nextState) {  
  2.     long timeoutOverride = originalTimeoutOverride;  
  3.     ......  
  4.     long when = 0;  
  5.     if (timeoutOverride <= 0) { // 时间设置<=0时,此时系统会使用缺省的定时时间开启计时器  
  6.         switch (nextState)  
  7.         {  
  8.             case SCREEN_BRIGHT: // 新状态是BRIGHT,则when加上mKeylightDelay  
  9.                 when = now + mKeylightDelay;  
  10.                 break;  
  11.             case SCREEN_DIM: // 新状态是DIM,则when加上mDimDelay  
  12.             if (mDimDelay >= 0) {  
  13.                 when = now + mDimDelay;  
  14.                 break;  
  15.             }  
  16.             case SCREEN_OFF: // 新状态是OFF,则when加上mScreenOffDelay  
  17.                 synchronized (mLocks) {  
  18.                     when = now + mScreenOffDelay;  
  19.                 }  
  20.                 break;  
  21.             default:  
  22.                 when = now;  
  23.                 break;  
  24.         }  
  25.     } else { // 如果定时时间设定,即为timeoutOverride  
  26.         override: {  
  27.             if (timeoutOverride <= mScreenOffDelay) {  
  28.                 when = now + timeoutOverride;  
  29.                 nextState = SCREEN_OFF;  
  30.                 break override;  
  31.             }  
  32.             timeoutOverride -= mScreenOffDelay;  
  33.    if (mDimDelay >= 0) {  
  34.                 if (timeoutOverride <= mDimDelay) {  
  35.                     when = now + timeoutOverride;  
  36.                     nextState = SCREEN_DIM;  
  37.                     break override;  
  38.                 }  
  39.                 timeoutOverride -= mDimDelay;  
  40.             }  
  41.    when = now + timeoutOverride;  
  42.             nextState = SCREEN_BRIGHT;  
  43.         }  
  44.     }  
  45.     mHandler.removeCallbacks(mTimeoutTask); // 移除旧的mTimeoutTask时间  
  46.     mTimeoutTask.nextState = nextState; // 赋值状态  
  47.     mTimeoutTask.remainingTimeoutOverride = timeoutOverride > 0  
  48.                     ? (originalTimeoutOverride - timeoutOverride)  
  49.                     : -1;  
  50.     mHandler.postAtTime(mTimeoutTask, when); // 重新启动定时器,在when时间后执行mTimeoutTask任务  
  51.     mNextTimeout = when;  
  52. }  

在PowerManagerService的初始化函数中最终会通过setTimeoutLocked来启动定时器,当定时器到时间后就会执行mTimeoutTask任务,下面可以看看mTimeoutTask任务的定义:
TimeoutTask mTimeoutTask = new TimeoutTask();
mTimeoutTask定义为类型是TimeoutTask的对象,TimeoutTask如下所示:
[java]  view plain  copy
  1. private class TimeoutTask implements Runnable  
  2. {  
  3.     int nextState; // access should be synchronized on mLocks  
  4.     long remainingTimeoutOverride;  
  5.     public void run()  
  6.     {  
  7.         synchronized (mLocks) {  
  8.             if (nextState == -1) {  
  9.                 return;  
  10.             }  
  11.             mUserState = this.nextState;  
  12.             setPowerState(this.nextState | mWakeLockState); // 调用setPowerState来睡眠或唤醒系统  
  13.             long now = SystemClock.uptimeMillis();  
  14.             switch (this.nextState) // 更新定时器  
  15.             {  
  16.                 case SCREEN_BRIGHT: // 如果状态是BRIGHT,则更新定时器,是定时器在到期后执行SCREEN_DIM操作  
  17.                     if (mDimDelay >= 0) {  
  18.                         setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_DIM);  
  19.                         break;  
  20.                     }  
  21.                 case SCREEN_DIM: // 如果状态是DIM,则更新定时器,是定时器在到期后执行SCREEN_OFF操作  
  22.                     setTimeoutLocked(now, remainingTimeoutOverride, SCREEN_OFF);  
  23.                     break;  
  24.             }  
  25.         }  
  26.     }  
  27. }  

于是在PowerManagerService中通过定时器来切换屏幕的状态,同时也会调用setPowerState方法来睡眠或唤醒系统,而具体的屏幕亮度是如何实现的呢?
在setPowerState中使用了updateLightsLocked来更新屏幕的状态。
[java]  view plain  copy
  1. private void updateLightsLocked(int newState, int forceState) {  
  2.     final int oldState = mPowerState; // 将当前系统状态赋值于oldState  
  3.     ......  
  4.     final int realDifference = (newState ^ oldState); // 判断新状态和旧状态的不同之处  
  5.     final int difference = realDifference | forceState;  
  6.     if (difference == 0) {  
  7.         return;  
  8.     }  
  9.     int offMask = 0;  
  10.     int dimMask = 0;  
  11.     int onMask = 0;  
  12.     int preferredBrightness = getPreferredBrightness(); // 获取缺省的亮度值  
  13.     if ((difference & KEYBOARD_BRIGHT_BIT) != 0) { // 如果是键盘亮度不同,则更新offMask和onMask  
  14.         if ((newState & KEYBOARD_BRIGHT_BIT) == 0) {  
  15.             offMask |= KEYBOARD_BRIGHT_BIT;  
  16.         } else {  
  17.             onMask |= KEYBOARD_BRIGHT_BIT;  
  18.         }  
  19.     }  
  20.     if ((difference & BUTTON_BRIGHT_BIT) != 0) { // 如果是按键亮度不同,则更新offMask和onMask  
  21.         if ((newState & BUTTON_BRIGHT_BIT) == 0) {  
  22.             offMask |= BUTTON_BRIGHT_BIT;  
  23.         } else {  
  24.             onMask |= BUTTON_BRIGHT_BIT;  
  25.         }  
  26.     }  
  27.     if ((difference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) { // 如果是屏幕开启或点亮状态位不同  
  28. int nominalCurrentValue = -1// 当前亮度  
  29. if ((realDifference & (SCREEN_ON_BIT | SCREEN_BRIGHT_BIT)) != 0) {  
  30.             switch (oldState & (SCREEN_BRIGHT_BIT|SCREEN_ON_BIT)) { // 判断旧的状态  
  31.                 case SCREEN_BRIGHT_BIT | SCREEN_ON_BIT: // 如果旧状态是开启并点亮屏幕  
  32.                     nominalCurrentValue = preferredBrightness; // 则将preferredBrightness赋给nominalCurrentValue  
  33.                     break;  
  34.                 case SCREEN_ON_BIT: // 如果旧状态仅仅是开启屏幕  
  35.                     nominalCurrentValue = mScreenDim;  
  36.                     break;  
  37.                 case 0// 如果旧状态是关闭屏幕  
  38.                     nominalCurrentValue = Power.BRIGHTNESS_OFF;  
  39.                     break;  
  40.                 case SCREEN_BRIGHT_BIT:  
  41.                 default:  
  42.                     // not possible  
  43.                     nominalCurrentValue = (int)mScreenBrightness.curValue;  
  44.                     break;  
  45.             }  
  46.         }  
  47. int brightness = preferredBrightness;  
  48.         int steps = ANIM_STEPS;  
  49.         if ((newState & SCREEN_BRIGHT_BIT) == 0) { // 如果新状态不是点亮屏幕,即变暗屏幕或关闭屏幕  
  50.    // 此时会使用动画操作渐渐的使屏幕变暗或关闭,这里计算step  
  51.             // dim or turn off backlight, depending on if the screen is on  
  52.             // the scale is because the brightness ramp isn't linear and this biases  
  53.             // it so the later parts take longer.  
  54.             final float scale = 1.5f;  
  55.             float ratio = (((float)mScreenDim)/preferredBrightness);  
  56.             if (ratio > 1.0f) ratio = 1.0f;  
  57.             if ((newState & SCREEN_ON_BIT) == 0) {  
  58.                 if ((oldState & SCREEN_BRIGHT_BIT) != 0) {  
  59.                     // was bright  
  60.                     steps = ANIM_STEPS;  
  61.                 } else {  
  62.                     // was dim  
  63.                     steps = (int)(ANIM_STEPS*ratio*scale);  
  64.                 }  
  65.                 brightness = Power.BRIGHTNESS_OFF; // 如果新状态是关闭屏幕,则赋值brightness为Power.BRIGHTNESS_OFF  
  66.             } else {                               // brightness为新状态的亮度  
  67.                 if ((oldState & SCREEN_ON_BIT) != 0) {  
  68.                     // was bright  
  69.                     steps = (int)(ANIM_STEPS*(1.0f-ratio)*scale);  
  70.                 } else {  
  71.                     // was dim  
  72.                     steps = (int)(ANIM_STEPS*ratio);  
  73.                 }  
  74.                 if (mStayOnConditions != 0 && mBatteryService.isPowered(mStayOnConditions)) {  
  75.                     // If the "stay on while plugged in" option is  
  76.                     // turned on, then the screen will often not  
  77.                     // automatically turn off while plugged in.  To  
  78.                     // still have a sense of when it is inactive, we  
  79.                     // will then count going dim as turning off.  
  80.                     mScreenOffTime = SystemClock.elapsedRealtime();  
  81.                     mAlwaysOnAndDimmed = true;  
  82.                 }  
  83.                 brightness = mScreenDim; // 如果新状态是变暗屏幕,则赋值brightness为mScreenDim  
  84.             }  
  85.         }  
  86. if (!mSkippedScreenOn) {  
  87.             mScreenBrightness.setTargetLocked(brightness, steps,  
  88.                     INITIAL_SCREEN_BRIGHTNESS, nominalCurrentValue); // 设置屏幕的亮度  
  89.         }  
  90.     }  
  91.     // 以下根据bit位的不同调用setLightBrightness来设置亮度,包括屏幕、键盘和按键  
  92.     if (offMask != 0) {  
  93.         setLightBrightness(offMask, Power.BRIGHTNESS_OFF);  
  94.     }  
  95.     if (dimMask != 0) {  
  96.         int brightness = mScreenBrightnessDim;  
  97.         if ((newState & BATTERY_LOW_BIT) != 0 &&  
  98.                 brightness > Power.BRIGHTNESS_LOW_BATTERY) {  
  99.             brightness = Power.BRIGHTNESS_LOW_BATTERY;  
  100.         }  
  101.         setLightBrightness(dimMask, brightness);  
  102.     }  
  103.     if (onMask != 0) {  
  104.         int brightness = getPreferredBrightness();  
  105.         if ((newState & BATTERY_LOW_BIT) != 0 &&  
  106.                 brightness > Power.BRIGHTNESS_LOW_BATTERY) {  
  107.             brightness = Power.BRIGHTNESS_LOW_BATTERY;  
  108.         }  
  109.         setLightBrightness(onMask, brightness);  
  110.     }  
  111. }  

在updateLightsLocked方法中使用了mScreenBrightness.setTargetLocked方法来设置屏幕的亮度,而mScreenBrightness是类型为BrightnessState的对象,以下是其定义:
private final BrightnessState mScreenBrightness = new BrightnessState(SCREEN_BRIGHT_BIT);
此类是通过逐渐减少step值的亮度来是的屏幕到达最终的亮度,下面分析setTargetLocked方法
[java]  view plain  copy
  1. void setTargetLocked(int target, int stepsToTarget, int initialValue,  
  2.         int nominalCurrentValue) {  
  3.     if (!initialized) { // 如果正在进行且目标亮度相同则返回  
  4.         initialized = true;  
  5.         curValue = (float)initialValue;  
  6.     } else if (targetValue == target) {  
  7.         return;  
  8.     }  
  9.     targetValue = target;  
  10.     delta = (targetValue -  
  11.             (nominalCurrentValue >= 0 ? nominalCurrentValue : curValue))  
  12.             / stepsToTarget; // 计算delta值  
  13.     animating = true;  
  14.     mScreenOffHandler.removeCallbacks(this); // 移除旧的事件  
  15.     mScreenOffHandler.post(this); // 开始新的事件  
  16. }  

其中mScreenOffHandler移除或开始的事件即为mScreenBrightness本身,此时会执行BrightnessState类中的run方法。
[java]  view plain  copy
  1. public void run() {  
  2.     synchronized (mLocks) {  
  3.         final boolean turningOn = animating && (int)curValue == Power.BRIGHTNESS_OFF; // 是否是打开屏幕  
  4.         final boolean turningOff = animating && targetValue == Power.BRIGHTNESS_OFF; // 是否是关闭屏幕  
  5.         // Check for the electron beam for fully on/off transitions.  
  6.         // Otherwise, allow it to fade the brightness as normal.  
  7.         final boolean electrifying =  
  8.                 ((mElectronBeamAnimationOff && turningOff) ||  
  9.                  (mElectronBeamAnimationOn && turningOn));  
  10.         if (!electrifying && (mAnimateScreenLights || !turningOff)) {   
  11.             long now = SystemClock.uptimeMillis();  
  12.             boolean more = mScreenBrightness.stepLocked(); // 使用stepLocked逐渐调至目标亮度  
  13.             if (more) {  
  14.                 mScreenOffHandler.postAtTime(this, now+(1000/60));  
  15.             }  
  16.          } else {  
  17.             // It's pretty scary to hold mLocks for this long, and we should  
  18.             // redesign this, but it works for now.  
  19.             if (turningOff) {  
  20.                 if (electrifying) {  
  21.                     nativeStartSurfaceFlingerOffAnimation(  
  22.                             mScreenOffReason == WindowManagerPolicy.OFF_BECAUSE_OF_PROX_SENSOR  
  23.                             ? 0 : mAnimationSetting);  
  24.                 }  
  25.                 mScreenBrightness.jumpToTargetLocked(); // 直接变成目标亮度  
  26.             } else if (turningOn) {  
  27.                 if (electrifying) {  
  28.                     int delay=mContext.getResources().getInteger(com.android.internal.R.integer.config_screenOnAnimation);  
  29.                     if(delay>0) {  
  30.                         startElectronBeamDelayed(new Runnable() {  
  31.                             @Override  
  32.                             public void run() {  
  33.                                 startElectronBeamOnAnimation();  
  34.                                 synchronized(mElectronBeamOnHandler) {  
  35.                                     mElectronBeamOnHandler.notifyAll();  
  36.                                 }  
  37.                             }  
  38.                         },delay);  
  39.                     } else {  
  40.                         startElectronBeamOnAnimation();  
  41.                     }  
  42.                 } else {  
  43.                     mScreenBrightness.jumpToTargetLocked(); // 直接变成目标亮度  
  44.                 }  
  45.             }  
  46.         }  
  47.     }  
  48. }  

在run方法中,不论是逐渐调制目标亮度stepLocked,或者直接变成目标亮度jumpToTargetLocked,都会调用到setLightBrightness方法用于改变亮度,下面来分析setLightBrightness方法。
[java]  view plain  copy
  1. private void setLightBrightness(int mask, int value) {  
  2.     int brightnessMode = (mAutoBrightessEnabled  
  3.                         ? LightsService.BRIGHTNESS_MODE_SENSOR  
  4.                         : LightsService.BRIGHTNESS_MODE_USER);  
  5.     if ((mask & SCREEN_BRIGHT_BIT) != 0) { // 如果是屏幕亮度,则使用mLcdLight.setBrightness  
  6.         mLcdLight.setBrightness(value, brightnessMode);  
  7.         mLastLcdValue = value;  
  8.     }  
  9.     if ((mask & BUTTON_BRIGHT_BIT) != 0) { // 如果是按键亮度,则使用mButtonLight.setBrightness  
  10.         // Use sensor-determined brightness values when the button (or keyboard)  
  11.         // light is on, since users may want to specify a custom brightness setting  
  12.         // that disables the button (or keyboard) backlight entirely in low-ambient  
  13.         // light situations.  
  14.         mButtonLight.setBrightness(mLightSensorButtonBrightness >= 0 && value > 0 ?  
  15.                                    mLightSensorButtonBrightness : value);  
  16.   
  17.   
  18.     }  
  19.     if ((mask & KEYBOARD_BRIGHT_BIT) != 0) { // 如果是键盘亮度,则使用mKeyboardLight.setBrightness  
  20.         mKeyboardLight.setBrightness(mLightSensorKeyboardBrightness >= 0 && value > 0 ?  
  21.                                          mLightSensorKeyboardBrightness : value);  
  22.     }  
  23. }  

在setLightBrightness方法中会根据mask的值来相应的改变屏幕、键盘和按键的亮度,屏幕的亮度主要使用mLcdLight.setBrightness方法,其中mLcdLight是类型为LightsService.Light的对象,在PowerManagerService的初始化函数中进行了赋值:
mLcdLight = lights.getLight(LightsService.LIGHT_ID_BACKLIGHT);
LightsService.Light类型定义在framework/base/services/java/com/android/server/LightsService.java中,下面来分析其setBrightness方法:
[java]  view plain  copy
  1. public void setBrightness(int brightness, int brightnessMode) {  
  2.     synchronized (this) {  
  3.         int color = brightness & 0x000000ff;  
  4.         color = 0xff000000 | (color << 16) | (color << 8) | color;  
  5.         setLightLocked(color, LIGHT_FLASH_NONE, 00, brightnessMode);  
  6.     }  
  7. }  

在setBrightness方法中,主要是将亮度值扩展成32bit的color值来提供给setLightLocked处理。
[java]  view plain  copy
  1. private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {  
  2.     if (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) {  
  3.         mColor = color;  
  4.         mMode = mode;  
  5.         mOnMS = onMS;  
  6.         mOffMS = offMS;  
  7.         setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);  
  8.     }  
  9. }  

setLightLocked会调用setLight_native来将亮度值传递至jni层,setLight_native在文件framework/base/services/jni/com_android_server_LightsService.cpp中实现。
[cpp]  view plain  copy
  1. static void setLight_native(JNIEnv *env, jobject clazz, int ptr,  
  2.         int light, int colorARGB, int flashMode, int onMS, int offMS, int brightnessMode)  
  3. {  
  4.     Devices* devices = (Devices*)ptr;  
  5.     light_state_t state;  
  6.   
  7.   
  8.     if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {  
  9.         return ;  
  10.     }  
  11.     memset(&state, 0, sizeof(light_state_t));  
  12.     state.color = colorARGB;  
  13.     state.flashMode = flashMode;  
  14.     state.flashOnMS = onMS;  
  15.     state.flashOffMS = offMS;  
  16.     state.brightnessMode = brightnessMode;  
  17.     devices->lights[light]->set_light(devices->lights[light], &state);  
  18. }  

而setLight_native方法使用devices->lights[light]->set_light来设定亮度值。在com_android_server_LightsService.cpp的初始化函数中,会对devices进行初始化,如下所示:
[cpp]  view plain  copy
  1. static jint init_native(JNIEnv *env, jobject clazz)  
  2. {  
  3.     int err;  
  4.     hw_module_t* module;  
  5.     Devices* devices;  
  6.       
  7.     devices = (Devices*)malloc(sizeof(Devices));  
  8.   
  9.     err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);  
  10.     if (err == 0) {  
  11.         devices->lights[LIGHT_INDEX_BACKLIGHT]  
  12.                 = get_device(module, LIGHT_ID_BACKLIGHT);  
  13.         devices->lights[LIGHT_INDEX_KEYBOARD]  
  14.                 = get_device(module, LIGHT_ID_KEYBOARD);  
  15.         devices->lights[LIGHT_INDEX_BUTTONS]  
  16.                 = get_device(module, LIGHT_ID_BUTTONS);  
  17.         devices->lights[LIGHT_INDEX_BATTERY]  
  18.                 = get_device(module, LIGHT_ID_BATTERY);  
  19.         devices->lights[LIGHT_INDEX_NOTIFICATIONS]  
  20.                 = get_device(module, LIGHT_ID_NOTIFICATIONS);  
  21.         devices->lights[LIGHT_INDEX_ATTENTION]  
  22.                 = get_device(module, LIGHT_ID_ATTENTION);  
  23.         devices->lights[LIGHT_INDEX_BLUETOOTH]  
  24.                 = get_device(module, LIGHT_ID_BLUETOOTH);  
  25.         devices->lights[LIGHT_INDEX_WIFI]  
  26.                 = get_device(module, LIGHT_ID_WIFI);  
  27.     } else {  
  28.         memset(devices, 0, sizeof(Devices));  
  29.     }  
  30.   
  31.     return (jint)devices;  
  32. }  
  33.   
  34. static light_device_t* get_device(hw_module_t* module, char const* name)  
  35. {  
  36.     int err;  
  37.     hw_device_t* device;  
  38.     err = module->methods->open(module, name, &device);  
  39.     if (err == 0) {  
  40.         return (light_device_t*)device;  
  41.     } else {  
  42.         return NULL;  
  43.     }  
  44. }  

该方法使用hw_get_module来获取动态库模块,其中LIGHTS_HARDWARE_MODULE_ID在/hardware/libhardware/include/hardware/lights.h中声明:
#define LIGHTS_HARDWARE_MODULE_ID "lights"
所以在硬件抽象层,如果要编写lights的模块供上层使用,需要将自身命名为lights的模块,下面以hardware/msm7k/liblights/lights.c为例,在其中就声明了“lights”模块
[cpp]  view plain  copy
  1. const struct hw_module_t HAL_MODULE_INFO_SYM = {  
  2.     .tag = HARDWARE_MODULE_TAG,  
  3.     .version_major = 1,  
  4.     .version_minor = 0,  
  5.     .id = LIGHTS_HARDWARE_MODULE_ID,  
  6.     .name = "QCT MSM7K lights Module",  
  7.     .author = "Google, Inc.",  
  8.     .methods = &lights_module_methods,  
  9. };  

然后在com_android_server_LightsService.cpp的初始化函数中使用get_device来打开相应的设备,其调用了module->methods->open的方法,而在hardware/msm7k/liblights/lights.c也定义了回调函数:
[cpp]  view plain  copy
  1. static struct hw_module_methods_t lights_module_methods = {  
  2.     .open =  open_lights,  
  3. };  
  4.   
  5. static int open_lights(const struct hw_module_t* module, char const* name,  
  6.         struct hw_device_t** device)  
  7. {  
  8.     int (*set_light)(struct light_device_t* dev,  
  9.             struct light_state_t const* state);  
  10.   
  11.   
  12.     if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {  
  13.         set_light = set_light_backlight;  
  14.     }  
  15.     else if (0 == strcmp(LIGHT_ID_KEYBOARD, name)) {  
  16.         set_light = set_light_keyboard;  
  17.     }  
  18.     else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) {  
  19.         set_light = set_light_buttons;  
  20.     }  
  21.     else if (0 == strcmp(LIGHT_ID_BATTERY, name)) {  
  22.         set_light = set_light_battery;  
  23.     }  
  24.     else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {  
  25.         set_light = set_light_notifications;  
  26.     }  
  27.     else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) {  
  28.         set_light = set_light_attention;  
  29.     }  
  30.     else {  
  31.         return -EINVAL;  
  32.     }  
  33.   
  34.     pthread_once(&g_init, init_globals);  
  35.   
  36.     struct light_device_t *dev = malloc(sizeof(struct light_device_t));  
  37.     memset(dev, 0, sizeof(*dev));  
  38.   
  39.     dev->common.tag = HARDWARE_DEVICE_TAG;  
  40.     dev->common.version = 0;  
  41.     dev->common.module = (struct hw_module_t*)module;  
  42.     dev->common.close = (int (*)(struct hw_device_t*))close_lights;  
  43.     dev->set_light = set_light;  
  44.   
  45.     *device = (struct hw_device_t*)dev;  
  46.     return 0;  
  47. }  

在open_lights方法中也映射了set_light方法,于是在com_android_server_LightsService.cpp的devices->lights[light]->set_light最终会调用hardware/msm7k/liblights/lights.c中set_light所映射的方法,set_light_backlight就是设置屏幕亮度的方法。
[cpp]  view plain  copy
  1. static int set_light_backlight(struct light_device_t* dev,  
  2.         struct light_state_t const* state)  
  3. {  
  4.     int err = 0;  
  5.     int brightness = rgb_to_brightness(state);  
  6.     pthread_mutex_lock(&g_lock);  
  7.     g_backlight = brightness;  
  8.     err = write_int(LCD_FILE, brightness);  
  9.     if (g_haveTrackballLight) {  
  10.         handle_trackball_light_locked(dev);  
  11.     }  
  12.     pthread_mutex_unlock(&g_lock);  
  13.     return err;  
  14. }  

其中char const*const LCD_FILE = "/sys/class/leds/lcd-backlight/brightness";
该方法会使用write_int函数将亮度写入至路径为LCD_FILE的文件中,即传递至内核层。

用户空间
//
内核空间

在内核空间中的kernel/drivers/leds/led-class.c模块初始化函数中,使用了class_create创建了“leds”类目录,同时在这个模块中给出了led_classdev_register用于注册led设备,除此之外,还给出了这个class下的相关属性:
[cpp]  view plain  copy
  1. // 模块初始化函数  
  2. static int __init leds_init(void)  
  3. {  
  4.     leds_class = class_create(THIS_MODULE, "leds");  
  5.     if (IS_ERR(leds_class))  
  6.     return PTR_ERR(leds_class);  
  7.     leds_class->suspend = led_suspend;  
  8.     leds_class->resume = led_resume;  
  9.     leds_class->dev_attrs = led_class_attrs;  
  10.     return 0;  
  11. }  
  12.   
  13. // led设备注册函数  
  14. int led_classdev_register(struct device *parent, struct led_classdev *led_cdev)  
  15. {  
  16.     led_cdev->dev = device_create(leds_class, parent, 0, led_cdev,  
  17.                       "%s", led_cdev->name);  
  18.     if (IS_ERR(led_cdev->dev))  
  19.     return PTR_ERR(led_cdev->dev);  
  20.   
  21. #ifdef CONFIG_LEDS_TRIGGERS  
  22.     init_rwsem(&led_cdev->trigger_lock);  
  23. #endif  
  24.     /* add to the list of leds */  
  25.     down_write(&leds_list_lock);  
  26.     list_add_tail(&led_cdev->node, &leds_list);  
  27.     up_write(&leds_list_lock);  
  28.     if (!led_cdev->max_brightness)  
  29.     led_cdev->max_brightness = LED_FULL;  
  30.     led_update_brightness(led_cdev);  
  31.     init_timer(&led_cdev->blink_timer);  
  32.     led_cdev->blink_timer.function = led_timer_function;  
  33.     led_cdev->blink_timer.data = (unsigned long)led_cdev;  
  34. #ifdef CONFIG_LEDS_TRIGGERS  
  35.     led_trigger_set_default(led_cdev);  
  36. #endif  
  37.     printk(KERN_DEBUG "Registered led device: %s\n",  
  38.         led_cdev->name);  
  39.     return 0;  
  40. }  
  41. EXPORT_SYMBOL_GPL(led_classdev_register);  
  42.   
  43. // led属性  
  44. static struct device_attribute led_class_attrs[] = {  
  45.     __ATTR(brightness, 0644, led_brightness_show, led_brightness_store),   
  46.     __ATTR(max_brightness, 0444, led_max_brightness_show, NULL),  
  47. #ifdef CONFIG_LEDS_TRIGGERS  
  48.     __ATTR(trigger, 0644, led_trigger_show, led_trigger_store),  
  49. #endif  
  50.     __ATTR_NULL,  
  51. };  

//
leds-lm3530.c模块为例子(有regulator)
在kernel/drivers/leds/leds-lm3530.c模块中,声明了名称为“lcd-backlight”的led设备,
并使用了led_classdev_register将其注册进入led class中。
[cpp]  view plain  copy
  1. drvdata->mode = pdata->mode;  
  2. drvdata->client = client;  
  3. drvdata->pdata = pdata;  
  4. drvdata->brightness = LED_OFF;  
  5. drvdata->enable = false;  
  6. drvdata->led_dev.name = LM3530_LED_DEV; // #define LM3530_LED_DEV "lcd-backlight"  
  7. drvdata->led_dev.brightness_set = lm3530_brightness_set;  
  8. i2c_set_clientdata(client, drvdata);  
  9. drvdata->regulator = regulator_get(&client->dev, "vin");  
  10. err = led_classdev_register(&client->dev, &drvdata->led_dev);  

于是就会产生/sys/class/leds/lcd-backlight/brightness的目录,所以上层使用write_int(LCD_FILE, brightness)向内核写入亮度值会调用kernel/drivers/leds/led-class.c模块中的led_brightness_store方法。
[cpp]  view plain  copy
  1. static ssize_t led_brightness_store(struct device *dev,  
  2. struct device_attribute *attr, const char *buf, size_t size)  
  3. {  
  4.     struct led_classdev *led_cdev = dev_get_drvdata(dev); // 此处的led_cdev就是kernel/drivers/staging/msm/msm_fb.c中注册的backlight_led  
  5.     ssize_t ret = -EINVAL;  
  6.     char *after;  
  7.     unsigned long state = simple_strtoul(buf, &after, 10);  
  8.     size_t count = after - buf;  
  9.     if (isspace(*after))  
  10. count++;  
  11.     if (count == size) {  
  12. ret = count;  
  13. if (state == LED_OFF)  
  14.    led_trigger_remove(led_cdev);  
  15. led_set_brightness(led_cdev, state); // 设置屏幕亮度  
  16.     }  
  17.     return ret;  
  18. }  

该方法调用led_set_brightness设置屏幕亮度,其在kernel/drivers/leds/leds.h中
[cpp]  view plain  copy
  1. static inline void led_set_brightness(struct led_classdev *led_cdev,  
  2. enum led_brightness value)  
  3. {  
  4.     if (value > led_cdev->max_brightness)  
  5. value = led_cdev->max_brightness;  
  6.     led_cdev->brightness = value;  
  7.     if (!(led_cdev->flags & LED_SUSPENDED))  
  8.         led_cdev->brightness_set(led_cdev, value); // 此处的led_cdev就是kernel/drivers/staging/msm/msm_fb.c中注册的backlight_led  
  9. }  

于是就调用了kernel/drivers/leds/leds-lm3530.c模块中的回调函数brightness_set,即lm3530_brightness_set函数
[cpp]  view plain  copy
  1. static void lm3530_brightness_set(struct led_classdev *led_cdev,  
  2.     enum led_brightness brt_val)  
  3. {  
  4.     int err;  
  5.     struct lm3530_data *drvdata = container_of(led_cdev, struct lm3530_data, led_dev);  
  6.     switch (drvdata->mode) {  
  7.     case LM3530_BL_MODE_MANUAL:  
  8.         if (!drvdata->enable) {  
  9.    err = lm3530_init_registers(drvdata); // 如果没有使能则会先使能,在这个方法中会调用regulator_enable来开启regulator输出  
  10.    if (err) {  
  11.        dev_err(&drvdata->client->dev, "Register Init failed: %d\n", err);  
  12.        break;  
  13.    }  
  14.         }  
  15.         /* set the brightness in brightness control register*/  
  16.         err = i2c_smbus_write_byte_data(drvdata->client,  
  17.        LM3530_BRT_CTRL_REG, brt_val / 2); // 设置亮度  
  18.         if (err)  
  19.    dev_err(&drvdata->client->dev, "Unable to set brightness: %d\n", err);  
  20.         else  
  21.    drvdata->brightness = brt_val / 2;  
  22.         if (brt_val == 0) {  
  23.    err = regulator_disable(drvdata->regulator); // 如果设置亮光为0,则会调用regulator_disable来关闭regulator输出  
  24.    if (err)  
  25.        dev_err(&drvdata->client->dev, "Disable regulator failed\n");  
  26.    drvdata->enable = false;  
  27. }  
  28. break;  
  29.     case LM3530_BL_MODE_ALS:  
  30. break;  
  31.     case LM3530_BL_MODE_PWM:  
  32. break;  
  33.     default:  
  34. break;  
  35.     }  
  36. }  

lm3530_brightness_set方法在打开屏幕时会使用regulator_enable开启电源管理芯片的regulator输出,在关闭屏幕时会调用regulator_disable关闭电源管理芯片的regulator输出,在调整屏幕亮度时使用i2c_smbus_write_byte_data向寄存器中写入数值来调整亮度。

///
msm_fb.c模块为例子(无regulator)
在kernel/drivers/staging/msm/msm_fb.c模块中,声明了名称为“lcd-backlight”的led设备,并使用了led_classdev_register将其注册进入led class中。
[cpp]  view plain  copy
  1. static struct led_classdev backlight_led = {  
  2. .name = "lcd-backlight",  
  3. .brightness = MAX_BACKLIGHT_BRIGHTNESS,  
  4. .brightness_set= msm_fb_set_bl_brightness,  
  5. };  
于是就会产生/sys/class/leds/lcd-backlight/brightness的目录,所以上层使用write_int(LCD_FILE, brightness)向内核写入亮度值会调用kernel/drivers/leds/led-class.c模块中的led_brightness_store方法。
[cpp]  view plain  copy
  1. static ssize_t led_brightness_store(struct device *dev,  
  2. struct device_attribute *attr, const char *buf, size_t size)  
  3. {  
  4.     struct led_classdev *led_cdev = dev_get_drvdata(dev); // 此处的led_cdev就是kernel/drivers/staging/msm/msm_fb.c中注册的backlight_led  
  5.     ssize_t ret = -EINVAL;  
  6.     char *after;  
  7.     unsigned long state = simple_strtoul(buf, &after, 10);  
  8.     size_t count = after - buf;  
  9.     if (isspace(*after))  
  10. count++;  
  11.     if (count == size) {  
  12. ret = count;  
  13. if (state == LED_OFF)  
  14.    led_trigger_remove(led_cdev);  
  15. led_set_brightness(led_cdev, state); // 设置屏幕亮度  
  16.     }  
  17.     return ret;  
  18. }  

该方法调用led_set_brightness设置屏幕亮度,其在kernel/drivers/leds/leds.h中
[cpp]  view plain  copy
  1. static inline void led_set_brightness(struct led_classdev *led_cdev,  
  2. enum led_brightness value)  
  3. {  
  4.     if (value > led_cdev->max_brightness)  
  5. value = led_cdev->max_brightness;  
  6.     led_cdev->brightness = value;  
  7.     if (!(led_cdev->flags & LED_SUSPENDED))  
  8.         led_cdev->brightness_set(led_cdev, value); // 此处的led_cdev就是kernel/drivers/staging/msm/msm_fb.c中注册的backlight_led  
  9. }  

于是就调用了kernel/drivers/staging/msm/msm_fb.c模块中的回调函数brightness_set,即msm_fb_set_bl_brightness函数
[cpp]  view plain  copy
  1. static void msm_fb_set_bl_brightness(struct led_classdev *led_cdev,  
  2. enum led_brightness value)  
  3. {  
  4.     struct msm_fb_data_type *mfd = dev_get_drvdata(led_cdev->dev->parent);  
  5.     int bl_lvl;  
  6.     if (value > MAX_BACKLIGHT_BRIGHTNESS)  
  7. value = MAX_BACKLIGHT_BRIGHTNESS;  
  8.     /* This maps android backlight level 0 to 255 into 
  9.        driver backlight level 0 to bl_max with rounding */  
  10.     bl_lvl = (2 * value * mfd->panel_info.bl_max + MAX_BACKLIGHT_BRIGHTNESS)  
  11.    /(2 * MAX_BACKLIGHT_BRIGHTNESS);  
  12.     if (!bl_lvl && value)  
  13.         bl_lvl = 1;  
  14.     msm_fb_set_backlight(mfd, bl_lvl, 1);  
  15. }  

在msm_fb_set_bl_brightness函数中将亮度从0-255映射成0-bl_max,然后使用msm_fb_set_backlight设置屏幕亮度
[cpp]  view plain  copy
  1. void msm_fb_set_backlight(struct msm_fb_data_type *mfd, __u32 bkl_lvl, u32 save)  
  2. {  
  3.     struct msm_fb_panel_data *pdata;  
  4.     pdata = (struct msm_fb_panel_data *)mfd->pdev->dev.platform_data;  
  5.     if ((pdata) && (pdata->set_backlight)) {  
  6. down(&mfd->sem);  
  7. if ((bkl_lvl != mfd->bl_level) || (!save)) {  
  8.    u32 old_lvl;  
  9.    old_lvl = mfd->bl_level;  
  10.    mfd->bl_level = bkl_lvl;  
  11.    pdata->set_backlight(mfd);  
  12.    if (!save)  
  13. mfd->bl_level = old_lvl;  
  14.    }  
  15. up(&mfd->sem);  
  16.     }  
  17. }  

在msm_fb_set_backlight方法中主要调用了各个具体设备的set_backlight回调函数,实现了lcd屏幕的亮度调节。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值