在上层可以通过设置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 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.
*
* The display power controller makes a copy of the provided object and then
* begins adjusting the power state to match what was requested.
*
*
* @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);
}
}
在animateScreenBrightness中 mScreenBrightnessRampAnimator是一个RampAnimator类型的DisplayPowerState对象
DisplayPowerController.java
private RampAnimator mScreenBrightnessRampAnimator;
private void animateScreenBrightness(int target, int rate) {
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
try {
mBatteryStats.noteScreenBrightness(target);
} catch (RemoteException ex) {
// same process
}
}
}
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;
}
RampAnimator.java中的mProperty.setValue(mObject, target);后面就是对应的DisplayPowerState 中的setScreenBrightness实现方法
public static final IntProperty SCREEN_BRIGHTNESS =
new IntProperty("screenBrightness") {
@Override
public void setValue(DisplayPowerState object, int value) {
object.setScreenBrightness(value);
}
@Override
public Integer get(DisplayPowerState object) {
return object.getScreenBrightness();
}
};
public void setScreenBrightness(int brightness) {
if (mScreenBrightness != brightness) {
mScreenBrightness = brightness;
if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
scheduleScreenUpdate();
}
}
}
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;