在上層可以通過設置screenBrightness 來實現背光亮度調節。
MAX_SCREEN_BRIGHTNESS爲255,brightness 在0和255之間
WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
lp.screenBrightness = brightness * 1.0f / MAX_SCREEN_BRIGHTNESS;
activity.getWindow().setAttributes(lp);
在WindowManager中連同其他參數一起寫入Parcel
public void writeToParcel(Parcel out, int parcelableFlags) {
out.writeInt(width);
out.writeInt(height);
out.writeInt(x);
out.writeInt(y);
....
out.writeInt(format);
out.writeInt(windowAnimations);
out.writeFloat(alpha);
out.writeFloat(dimAmount);
out.writeFloat(screenBrightness);
out.writeFloat(buttonBrightness);
....
out.writeLong(userActivityTimeout);
out.writeInt(surfaceInsets.left);
out.writeInt(surfaceInsets.top);
out.writeInt(surfaceInsets.right);
out.writeInt(surfaceInsets.bottom);
...
out.writeInt(needsMenuKey);
out.writeInt(accessibilityIdOfAnchor);
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
out.writeInt(mColorMode);
out.writeLong(hideTimeoutMilliseconds);
}
之後進入到frameworks\base\services\core\java\com\android\server\wm\RootWindowContainer.java中
判斷mService顯示是否已經凍結,之後判斷mScreenBrightness 是否介於0和1之間,如果是則將brightness這個值handle傳遞處理
private float mScreenBrightness = -1;
WindowManagerService mService;
RootWindowContainer(WindowManagerService service) {
mService = service;
mHandler = new MyHandler(service.mH.getLooper());
mLayersController = new WindowLayersController(mService);
mWallpaperController = new WallpaperController(mService);
}
void performSurfacePlacement(boolean recoveringMemory) {
.....
mScreenBrightness = -1;
....
final DisplayContent defaultDisplay = mService.getDefaultDisplayContentLocked();
final DisplayInfo defaultInfo = defaultDisplay.getDisplayInfo();
....
if (!mService.mDisplayFrozen) {
final int brightness = mScreenBrightness < 0 || mScreenBrightness > 1.0f
? -1 : toBrightnessOverride(mScreenBrightness);
mHandler.obtainMessage(SET_SCREEN_BRIGHTNESS_OVERRIDE, brightness, 0).sendToTarget();
mHandler.obtainMessage(SET_USER_ACTIVITY_TIMEOUT, mUserActivityTimeout).sendToTarget();
}
在RootWindowContainer中handleNotObscuredLocked用來讀取 WindowManager.LayoutParams設置的亮度值 ,首先判斷surface是否存在和可見,之後判斷syswin(與WindowManager.LayoutParams中的type類型相關)及亮度值是否合理纔會設值
/**
* @param w WindowState this method is applied to.
* @param obscured True if there is a window on top of this obscuring the display.
* @param syswin System window?
* @return True when the display contains content to show the user. When false, the display
* manager may choose to mirror or blank the display.
*/
boolean handleNotObscuredLocked(WindowState w, boolean obscured, boolean syswin) {
final WindowManager.LayoutParams attrs = w.mAttrs;
final int attrFlags = attrs.flags;
final boolean canBeSeen = w.isDisplayedLw();
final int privateflags = attrs.privateFlags;
boolean displayHasContent = false;
if (w.mHasSurface && canBeSeen) {
...
if (!syswin && w.mAttrs.screenBrightness >= 0 && mScreenBrightness < 0) {
mScreenBrightness = w.mAttrs.screenBrightness;
}
if (!syswin && w.mAttrs.userActivityTimeout >= 0 && mUserActivityTimeout < 0) {
mUserActivityTimeout = w.mAttrs.userActivityTimeout;
}
....
}
syswin設值的地方就兩個另外一個DisplayContent的內部類ApplySurfaceChangesTransactionState的reset方法syswin置爲false
frameworks\base\services\core\java\com\android\server\wm\DisplayContent.java
private final Consumer<WindowState> mApplySurfaceChangesTransaction = w -> {
...
mTmpApplySurfaceChangesTransactionState.displayHasContent |=
root.handleNotObscuredLocked(w,
mTmpApplySurfaceChangesTransactionState.obscured,
mTmpApplySurfaceChangesTransactionState.syswin);
if (w.mHasSurface && isDisplayed) {
final int type = w.mAttrs.type;
if (type == TYPE_SYSTEM_DIALOG || type == TYPE_SYSTEM_ERROR
|| (w.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
mTmpApplySurfaceChangesTransactionState.syswin = true;
}
....
}
...
...
}
根據SET_SCREEN_BRIGHTNESS_OVERRIDE 調用setScreenBrightnessOverrideFromWindowManager來實現亮度值的設置
private final class MyHandler extends Handler {
public MyHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SET_SCREEN_BRIGHTNESS_OVERRIDE:
mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
msg.arg1);
break;
case SET_USER_ACTIVITY_TIMEOUT:
mService.mPowerManagerInternal.setUserActivityTimeoutOverrideFromWindowManager(
(Long) msg.obj);
break;
default:
break;
}
}
}
mService.mPowerManagerInternal.setScreenBrightnessOverrideFromWindowManager(
msg.arg1);
其中PowerManagerInternal是一個抽象類
/**
* Used by the window manager to override the screen brightness based on the
* current foreground activity.
*
* This method must only be called by the window manager.
*
* @param brightness The overridden brightness, or -1 to disable the override.
*/
public abstract void setScreenBrightnessOverrideFromWindowManager(int brightness);
起具體實現是在PowerManagerService中bringhtness保存在
mScreenBrightnessOverrideFromWindowManager同時更新狀態updatePowerStateLocked
frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java
private final class LocalService extends PowerManagerInternal {
@Override
public void setScreenBrightnessOverrideFromWindowManager(int screenBrightness) {
if (screenBrightness < PowerManager.BRIGHTNESS_DEFAULT
|| screenBrightness > PowerManager.BRIGHTNESS_ON) {
screenBrightness = PowerManager.BRIGHTNESS_DEFAULT;
}
setScreenBrightnessOverrideFromWindowManagerInternal(screenBrightness);
}
....
...
}
private void setScreenBrightnessOverrideFromWindowManagerInternal(int brightness) {
synchronized (mLock) {
if (mScreenBrightnessOverrideFromWindowManager != brightness) {
mScreenBrightnessOverrideFromWindowManager = brightness;
mDirty |= DIRTY_SETTINGS;
updatePowerStateLocked();
}
}
}
而mScreenBrightnessOverrideFromWindowManager這個值的調用是在
updatePowerStateLocked的updateDisplayPowerStateLocked中根據條件判斷設置哪個亮度值,然後將值設置進入mDisplayPowerRequest中
private boolean updateDisplayPowerStateLocked(int dirty) {
....
int screenBrightness = mScreenBrightnessSettingDefault;
boolean autoBrightness = (mScreenBrightnessModeSetting ==
Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
....
if (!mBootCompleted) {
// Keep the brightness steady during boot. This requires the
// bootloader brightness and the default brightness to be identical.
autoBrightness = false;
brightnessSetByUser = false;
} else if (mIsVrModeEnabled) {
screenBrightness = mScreenBrightnessForVrSetting;
autoBrightness = false;
} else if (isValidBrightness(mScreenBrightnessOverrideFromWindowManager)) {
screenBrightness = mScreenBrightnessOverrideFromWindowManager;
autoBrightness = false;
brightnessSetByUser = false;
} else if (isValidBrightness(mTemporaryScreenBrightnessSettingOverride)) {
screenBrightness = mTemporaryScreenBrightnessSettingOverride;
} else if (isValidBrightness(mScreenBrightnessSetting)) {
screenBrightness = mScreenBrightnessSetting;
}
....
screenBrightness = Math.max(Math.min(screenBrightness,
mScreenBrightnessSettingMaximum), mScreenBrightnessSettingMinimum);
screenAutoBrightnessAdjustment = Math.max(Math.min(
screenAutoBrightnessAdjustment, 1.0f), -1.0f);
....
// Update display power request.
mDisplayPowerRequest.screenBrightness = screenBrightness;
mDisplayPowerRequest.screenAutoBrightnessAdjustment =
screenAutoBrightnessAdjustment;
mDisplayPowerRequest.brightnessSetByUser = brightnessSetByUser;
mDisplayPowerRequest.useAutoBrightness = autoBrightness;
mDisplayPowerRequest.useProximitySensor = shouldUseProximitySensorLocked();
mDisplayPowerRequest.boostScreenBrightness = shouldBoostScreenBrightness();
....
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
....
}
DisplayManagerInternal的requestPowerState
/**
* Called by the power manager to request a new power state.
* <p>
* The display power controller makes a copy of the provided object and then
* begins adjusting the power state to match what was requested.
* </p>
*
* @param request The requested power state.
* @param waitForNegativeProximity If true, issues a request to wait for
* negative proximity before turning the screen back on, assuming the screen
* was turned off by the proximity sensor.
* @return True if display is ready, false if there are important changes that must
* be made asynchronously (such as turning the screen on), in which case the caller
* should grab a wake lock, watch for {@link DisplayPowerCallbacks#onStateChanged()}
* then try the request again later until the state converges.
*/
public abstract boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity);
public final class DisplayManagerService extends SystemService {
...
private final class LocalService extends DisplayManagerInternal {
...
@Override
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
return mDisplayPowerController.requestPowerState(request,
waitForNegativeProximity);
}
...
}
...
}
繼續推進是在DisplayPowerController的requestPowerState中將request中的參數解析出保存,然後
sendUpdatePowerStateLocked
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
...
synchronized (mLock) {
boolean changed = false;
...
if (mPendingRequestLocked == null) {
mPendingRequestLocked = new DisplayPowerRequest(request);
changed = true;
} else if (!mPendingRequestLocked.equals(request)) {
mPendingRequestLocked.copyFrom(request);
changed = true;
}
...
if (changed) {
mDisplayReadyLocked = false;
}
if (changed && !mPendingRequestChangedLocked) {
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked();
}
...
private void sendUpdatePowerStateLocked() {
if (!mPendingUpdatePowerStateLocked) {
mPendingUpdatePowerStateLocked = true;
Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);
msg.setAsynchronous(true);
mHandler.sendMessage(msg);
}
}
通過MSG_UPDATE_POWER_STATE來updatePowerState();讀取brightness設置進入animateScreenBrightness
private void updatePowerState() {
...
// Use default brightness when dozing unless overridden.
if (brightness < 0 && (state == Display.STATE_DOZE
|| state == Display.STATE_DOZE_SUSPEND)) {
brightness = mScreenBrightnessDozeConfig;
}
...
// Apply manual brightness.
// Use the current brightness setting from the request, which is expected
// provide a nominal default value for the case where auto-brightness
// is not ready yet.
if (brightness < 0) {
brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
}
...
boolean wasOrWillBeInVr = (state == Display.STATE_VR || oldState == Display.STATE_VR);
if ((state == Display.STATE_ON
&& mSkipRampState == RAMP_STATE_SKIP_NONE
|| state == Display.STATE_DOZE && !mBrightnessBucketsInDozeConfig)
&& !wasOrWillBeInVr) {
animateScreenBrightness(brightness,
slowChange ? mBrightnessRampRateSlow : mBrightnessRampRateFast);
} else {
animateScreenBrightness(brightness, 0);
}
}
frameworks\base\services\core\java\com\android\server\display\RampAnimator.java
/**
* Starts animating towards the specified value.
*
* If this is the first time the property is being set or if the rate is 0,
* the value jumps directly to the target.
*
* @param target The target value.
* @param rate The convergence rate in units per second, or 0 to set the value immediately.
* @return True if the target differs from the previous target.
*/
public boolean animateTo(int target, int rate) {
// Immediately jump to the target the first time.
if (mFirstTime || rate <= 0) {
if (mFirstTime || target != mCurrentValue) {
mFirstTime = false;
mRate = 0;
mTargetValue = target;
mCurrentValue = target;
mProperty.setValue(mObject, target);
if (mAnimating) {
mAnimating = false;
cancelAnimationCallback();
}
if (mListener != null) {
mListener.onAnimationEnd();
}
return true;
}
return false;
}
其中部分還未完全整理清楚
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java
private Runnable updateDisplayStateLocked(DisplayDevice device) {
// Blank or unblank the display immediately to match the state requested
// by the display power controller (if known).
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
return device.requestDisplayStateLocked(mGlobalDisplayState, mGlobalDisplayBrightness);
}
return null;
}
requestDisplayStateLocked該方法在LocalDisplayAdapter中的子線程調用setDisplayBrightness
private final class LocalDisplayDevice extends DisplayDevice {
private final Light mBacklight;
....
@Override
public Runnable requestDisplayStateLocked(final int state, final int brightness) {
...
// Assume that the brightness is off if the display is being turned off.
assert state != Display.STATE_OFF || brightness == PowerManager.BRIGHTNESS_OFF;
final boolean stateChanged = (mState != state);
final boolean brightnessChanged = (mBrightness != brightness) && mBacklight != null;
...
// Defer actually setting the display state until after we have exited
// the critical section since it can take hundreds of milliseconds
// to complete.
return new Runnable() {
@Override
public void run() {
...
// Apply brightness changes given that we are in a non-suspended state.
if (brightnessChanged || vrModeChange) {
setDisplayBrightness(brightness);
}
...
}
}
}
private void setDisplayBrightness(int brightness) {
...
mBacklight.setBrightness(brightness);
...
}
Light 在LightsService的內部類LightImpl實現setBrightness其中調用的是setLightLocked
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER);後面四個參數都爲0
setLight_native參數第一個ID 類型 ,第二個亮度值,後面都設成了0
frameworks\base\services\core\java\com\android\server\lights\LightsManager.java
public static final int LIGHT_ID_BACKLIGHT = Type.BACKLIGHT;
public static final int LIGHT_ID_KEYBOARD = Type.KEYBOARD;
public static final int LIGHT_ID_BUTTONS = Type.BUTTONS;
public static final int LIGHT_ID_BATTERY = Type.BATTERY;
public static final int LIGHT_ID_NOTIFICATIONS = Type.NOTIFICATIONS;
public static final int LIGHT_ID_ATTENTION = Type.ATTENTION;
public static final int LIGHT_ID_BLUETOOTH = Type.BLUETOOTH;
public static final int LIGHT_ID_WIFI = Type.WIFI;
public static final int LIGHT_ID_COUNT = Type.COUNT;
從BACKLIGHT的0 到 WIFI 7,
frameworks\base\services\core\java\com\android\server\lights\LightsService.java
private final class LightImpl extends Light {
private LightImpl(int id) {
mId = id;
}
...
@Override
public void setBrightness(int brightness) {
setBrightness(brightness, BRIGHTNESS_MODE_USER);
}
@Override
public void setBrightness(int brightness, int brightnessMode) {
synchronized (this) {
// LOW_PERSISTENCE cannot be manually set
if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mId +
": brightness=0x" + Integer.toHexString(brightness));
return;
}
int color = brightness & 0x000000ff;
color = 0xff000000 | (color << 16) | (color << 8) | color;
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
}
}
....
@Override
public void setColor(int color) {
synchronized (this) {
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0);
}
}
....
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
....
setLight_native(mId, color, mode, onMS, offMS, brightnessMode);
....
}
...
}
之後進入JNI
frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
static void setLight_native(
JNIEnv* /* env */,
jobject /* clazz */,
jint light,
jint colorARGB,
jint flashMode,
jint onMS,
jint offMS,
jint brightnessMode) {
...
onSetLightNative(NULL,NULL, ptr,light, colorARGB,flashMode, onMS, offMS, brightnessMode);
...
}
定義了背光節點 ,根據name打開對應的節點,通過write_int將亮度值寫入節點
vendor/mediatek/proprietary/hardware/liblights/lights.c
/* LCD BACKLIGHT */
char const*const LCD_FILE
= "/sys/class/leds/lcd-backlight/brightness";
static struct hw_module_methods_t lights_module_methods = {
.open = open_lights,
};
struct hw_module_t HAL_MODULE_INFO_SYM = {
.tag = HARDWARE_MODULE_TAG,
//.version_major = 1,
//.version_minor = 0,
.id = LIGHTS_HARDWARE_MODULE_ID,
.name = "MTK lights Module",
.author = "MediaTek",
.methods = &lights_module_methods,
};
/** Open a new instance of a lights device using name */
static int open_lights(const struct hw_module_t* module, char const* name,
struct hw_device_t** device){
...
if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {
set_light = set_light_backlight;
if (access(LCD_FILE, F_OK) < 0)
return -errno;
}
....
}
static int
set_light_backlight(struct light_device_t* dev,
struct light_state_t const* state)
{
int err = 0;
int brightness = rgb_to_brightness(state);
pthread_mutex_lock(&g_lock);
g_backlight = brightness;
err = write_int(LCD_FILE, brightness);
if (g_haveTrackballLight) {
handle_trackball_light_locked(dev);
}
err = write_int(LCD_FILE, brightness);
if (g_haveTrackballLight) {
handle_trackball_light_locked(dev);
}
}
////////////
static int
write_int(char const* path, int value)
{
int fd;
#ifdef LIGHTS_INFO_ON
ALOGD("write %d to %s", value, path);
#endif
fd = open(path, O_RDWR);
ALOGD("write_int open fd=%d\n", fd);
if (fd >= 0) {
char buffer[20];
int bytes = sprintf(buffer, "%d\n", value);
int amt = write(fd, buffer, bytes);
close(fd);
} else {
return -errno;
}
}
return amt == -1 ? -errno : 0;