前言
Android设备与用户进行交互往往通过屏幕进行,目前市场手机设备对于屏幕越来月看重,oled、高刷、大尺寸、全色域等都是各大厂商的pk项,目的都是为了提高设备的交互体验,同时现在大多数设备都已支持屏幕亮度自适应动态调节,自动根据环境亮度调节屏幕显示亮度。那么设备开机时屏幕是如何亮起来的呢?待机时屏幕是如何熄灭的呢?以及由室外走进室内屏幕亮度如何自适应调节呢?
本文基于Android 10从开机亮屏、关机熄屏和自动亮度调节三个方面介绍系统屏幕亮度控制实现。
一、开机亮屏流程
屏幕的控制主要涉及PowerManagerService(PMS)、DisplayManagerService(DMS)、DisplayPowerController(DPC)几个类,先讲讲这几个类的主要作用:
- PowerManagerService:负责管理,协调设备电源以及设备常用功能如亮灭屏、亮度调节、低电量模式、保持CPU唤醒等。
- DisplayManagerService:管理显示设备生命周期,添加,移除,状态更新,在状态更新时向系统和其他应用发送通知等。
- DisplayPowerController:用于控制显示电源状态,处理屏亮灭及其动画,背光调节等。
开机亮屏的时序图如下:
上述流程涉及的代码及路径如下:
frameworks\base\core\java\android\os\PowerManager.java
frameworks\base\core\java\android\view\SurfaceControl.java
frameworks\base\core\jni\android_view_SurfaceControl.cpp
frameworks\base\core\res\res\values\config.xml
frameworks\base\packages\SettingsProvider\res\values\defaults.xml
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java
frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java
frameworks\base\services\core\java\com\android\server\display\LocalDisplayAdapter.java
frameworks\base\services\core\java\com\android\server\display\RampAnimator.java
frameworks\base\services\core\java\com\android\server\lights\LightsService.java
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java
frameworks\base\services\java\com\android\server\SystemServer.java
frameworks\native\libs\gui\SurfaceComposerClient.cpp
frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp
frameworks\native\services\surfaceflinger\DisplayHardware\ComposerHal.cpp
hardware\qcom\display\sdm\libs\core\display_builtin.cpp
hardware\qcom\display\sdm\libs\core\drm\hw_peripheral_drm.cpp
hardware\qcom\display\sdm\libs\hwc2\hwc_session_services.cpp
hardware\qcom\display\sdm\libs\hwc2\hwc_session.cpp
hardware\qcom\display\sdm\libs\hwc2\hwc_display_builtin.cpp
1.1、DMS的启动
frameworks\base\services\java\com\android\server\SystemServer.java
DMS服务是在开机时由SystemServer启动的
private void startBootstrapServices() {
// Display manager is needed to provide display metrics before package manager
// starts up.
traceBeginAndSlog("StartDisplayManager");
mDisplayManagerService = mSystemServiceManager.startService(DisplayManagerService.class);//启动DMS服务,调用DMS onStart()
traceEnd();
// We need the default display before we can initialize the package manager.
traceBeginAndSlog("WaitForDisplay");
mSystemServiceManager.startBootPhase(SystemService.PHASE_WAIT_FOR_DEFAULT_DISPLAY);//等待DMS启动完成后调用DMS onBootPhase()
traceEnd();
}
接着进入DMS构造方法
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java
@VisibleForTesting
DisplayManagerService(Context context, Injector injector) {//启动DMS进入构造方法
super(context);
mInjector = injector;
mContext = context;
mHandler = new DisplayManagerHandler(DisplayThread.get().getLooper());
mUiHandler = UiThread.getHandler();
//创建mDisplayAdapterListener对象,继承自DisplayAdapter.Listener,负责给DMS传递各个DisplayAdapter中发出的事件
mDisplayAdapterListener = new DisplayAdapterListener();
//创建DisplayModeDirector对象,负责监听并选择系统中各类Display配置组合
mDisplayModeDirector = new DisplayModeDirector(context, mHandler);
...
PowerManager pm = mContext.getSystemService(PowerManager.class);
mGlobalDisplayBrightness = pm.getDefaultScreenBrightnessSetting();//获取系统默认亮度值
...
mSystemReady = false;
}
frameworks\base\core\java\android\os\PowerManager.java
@UnsupportedAppUsage
public int getDefaultScreenBrightnessSetting() {
return mContext.getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessSettingDefault);//从config.xml配置文件中获取默认系统亮度
}
frameworks\base\core\res\res\values\config.xml
<!-- Default screen brightness setting.
Must be in the range specified by minimum and maximum. -->
<integer name="config_screenBrightnessSettingDefault">102</integer>//默认亮度为102
另外SettingsProvider中也有默认值,存入android数据库,两者应当一致
frameworks\base\packages\SettingsProvider\res\values\defaults.xml
<!-- Default screen brightness, from 0 to 255. 102 is 40%. -->
<integer name="def_screen_brightness">102</integer>//默认亮度102
<bool name="def_screen_brightness_automatic_mode">false</bool>//默认自动亮度调节
1.2、添加显示设备
继续回到DMS,走完DMS构造方法,接着进入onStart()
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java
@Override
public void onStart() {
...
synchronized (mSyncRoot) {
//1、加载本地持久化数据
mPersistentDataStore.loadIfNeeded();
loadStableDisplayValuesLocked();
}
//2、发送MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS 消息,注册默认display_adapters
mHandler.sendEmptyMessage(MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS);
//3、对外公布Binder、Local服务
publishBinderService(Context.DISPLAY_SERVICE, new BinderService(),
true /*allowIsolated*/);
publishLocalService(DisplayManagerInternal.class, new LocalService());
}
...
private final class DisplayManagerHandler extends Handler {
public DisplayManagerHandler(Looper looper) {
super(looper, null, true /*async*/);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS:
registerDefaultDisplayAdapters();//接收onStart()发来的消息,并注册默认适配器
break;
case MSG_REGISTER_ADDITIONAL_DISPLAY_ADAPTERS:
registerAdditionalDisplayAdapters();//注册额外适配器
break;
case MSG_DELIVER_DISPLAY_EVENT:
deliverDisplayEvent(msg.arg1, msg.arg2);//分发Display事件
break;
...
case MSG_LOAD_BRIGHTNESS_CONFIGURATION:
loadBrightnessConfiguration();//加载并设置亮度配置数据
break;
}
}
}
private void registerDefaultDisplayAdapters() {
// Register default display adapters.
synchronized (mSyncRoot) {
// main display adapter
registerDisplayAdapterLocked(new LocalDisplayAdapter(
mSyncRoot, mContext, mHandler, mDisplayAdapterListener));
mVirtualDisplayAdapter = mInjector.getVirtualDisplayAdapter(mSyncRoot, mContext,
mHandler, mDisplayAdapterListener);
if (mVirtualDisplayAdapter != null) {
registerDisplayAdapterLocked(mVirtualDisplayAdapter);
}
}
}
private void registerDisplayAdapterLocked(DisplayAdapter adapter) {
mDisplayAdapters.add(adapter);
adapter.registerLocked();
}
LocalDisplayAdapter 继承 DisplayAdapter ,主要为本地显示设备提供的适配器
frameworks\base\services\core\java\com\android\server\display\LocalDisplayAdapter.java
@Override
public void registerLocked() {
super.registerLocked();
mPhysicalDisplayEventReceiver = new PhysicalDisplayEventReceiver(getHandler().getLooper());
for (long physicalDisplayId : SurfaceControl.getPhysicalDisplayIds()) {
tryConnectDisplayLocked(physicalDisplayId);//连接显示设备,传入物理设备id
}
}
private void tryConnectDisplayLocked(long physicalDisplayId) {
...
int[] colorModes = SurfaceControl.getDisplayColorModes(displayToken);
int[] allowedConfigs = SurfaceControl.getAllowedDisplayConfigs(displayToken);
LocalDisplayDevice device = mDevices.get(physicalDisplayId);
if (device == null) {
// Display was added.
final boolean isInternal = mDevices.size() == 0;
device = new LocalDisplayDevice(displayToken, physicalDisplayId,
configs, activeConfig, allowedConfigs, colorModes, activeColorMode,
isInternal);
mDevices.put(physicalDisplayId, device);
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_ADDED);//通知本地设备连接成功
} else if (device.updatePhysicalDisplayInfoLocked(configs, activeConfig,
allowedConfigs, colorModes, activeColorMode)) {
// Display properties changed.
sendDisplayDeviceEventLocked(device, DISPLAY_DEVICE_EVENT_CHANGED);
}
}
...
}
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java
private final class DisplayAdapterListener implements DisplayAdapter.Listener {
@Override
public void onDisplayDeviceEvent(DisplayDevice device, int event) {
switch (event) {
case DisplayAdapter.DISPLAY_DEVICE_EVENT_ADDED://添加显示设备
handleDisplayDeviceAdded(device);
break;
case DisplayAdapter.DISPLAY_DEVICE_EVENT_CHANGED://更改显示设备
handleDisplayDeviceChanged(device);
break;
case DisplayAdapter.DISPLAY_DEVICE_EVENT_REMOVED://异常显示设备
handleDisplayDeviceRemoved(device);
break;
}
}
private void handleDisplayDeviceAdded(DisplayDevice device) {
synchronized (mSyncRoot) {
handleDisplayDeviceAddedLocked(device);
}
}
private void handleDisplayDeviceAddedLocked(DisplayDevice device) {
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if (mDisplayDevices.contains(device)) {
Slog.w(TAG, "Attempted to add already added display device: " + info);
return;
}
device.mDebugLastLoggedDeviceInfo = info;
mDisplayDevices.add(device);
LogicalDisplay display = addLogicalDisplayLocked(device);
Runnable work = updateDisplayStateLocked(device);//更新本地显示设备状态
if (work != null) {
work.run();
}
scheduleTraversalLocked(false);
}
private Runnable updateDisplayStateLocked(DisplayDevice device) {
DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
//设置display全局状态和亮度值,mGlobalDisplayBrightness在上面构造函数中完成初始化
return device.requestDisplayStateLocked(mGlobalDisplayState, mGlobalDisplayBrightness);
}
return null;
}
frameworks\base\services\core\java\com\android\server\display\LocalDisplayAdapter.java
private final class LocalDisplayDevice extends DisplayDevice {
...
@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;
if (stateChanged || brightnessChanged) {
final long physicalDisplayId = mPhysicalDisplayId;
final IBinder token = getDisplayTokenLocked();
final int oldState = mState;
if (stateChanged) {
mState = state;
updateDeviceInfoLocked();//发送显示器状态改变消息
}
if (brightnessChanged) {
mBrightness = brightness;
}
// 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() {
// Exit a suspended state before making any changes.
int currentState = oldState;
if (Display.isSuspendedState(oldState)
|| oldState == Display.STATE_UNKNOWN) {
if (!Display.isSuspendedState(state)) {
setDisplayState(state);
currentState = state;
} else if (state == Display.STATE_DOZE_SUSPEND
|| oldState == Display.STATE_DOZE_SUSPEND) {
setDisplayState(Display.STATE_DOZE);
currentState = Display.STATE_DOZE;
} else if (state == Display.STATE_ON_SUSPEND
|| oldState == Display.STATE_ON_SUSPEND) {
setDisplayState(Display.STATE_ON);
currentState = Display.STATE_ON;
} else {
return; // old state and new state is off
}
}
// If the state change was from or to VR, then we need to tell the light
// so that it can apply appropriate VR brightness settings. Also, update the
// brightness so the state is propogated to light.
boolean vrModeChange = false;
if ((state == Display.STATE_VR || currentState == Display.STATE_VR) &&
currentState != state) {
setVrMode(state == Display.STATE_VR);
vrModeChange = true;
}
// Apply brightness changes given that we are in a non-suspended state.
if (brightnessChanged || vrModeChange) {
setDisplayBrightness(brightness);//设置显示亮度
}
// Enter the final desired state, possibly suspended.
if (state != currentState) {
setDisplayState(state);
}
}
private void setVrMode(boolean isVrEnabled) {
mBacklight.setVrMode(isVrEnabled);
}
private void setDisplayState(int state) {
...
}
private void setDisplayBrightness(int brightness) {
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
+ "id=" + physicalDisplayId + ", brightness=" + brightness + ")");
try {
mBacklight.setBrightness(brightness);
Trace.traceCounter(Trace.TRACE_TAG_POWER,
"ScreenBrightness", brightness);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
};
}
return null;
}
...
}
1.3、设置屏亮度数据
frameworks\base\services\core\java\com\android\server\lights\LightsService.java
@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;
}
// Ideally, we'd like to set the brightness mode through the SF/HWC as well, but
// right now we just fall back to the old path through Lights brightessMode is
// anything but USER or the device shouldBeInLowPersistenceMode().
if (brightnessMode == BRIGHTNESS_MODE_USER && !shouldBeInLowPersistenceMode()
&& mSurfaceControlMaximumBrightness == 255) {
// TODO: the last check should be mSurfaceControlMaximumBrightness != 0; the
// reason we enforce 255 right now is to stay consistent with the old path. In
// the future, the framework should be refactored so that brightness is a float
// between 0.0f and 1.0f, and the actual number of supported brightness levels
// is determined in the device-specific implementation.
//通过SF(Surface)来设置显示亮度
SurfaceControl.setDisplayBrightness(mDisplayToken,
(float) brightness / mSurfaceControlMaximumBrightness);
} else {
int color = brightness & 0x000000ff;
color = 0xff000000 | (color << 16) | (color << 8) | color;
//最终调用Light HAL来设置显示亮度
setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
}
}
}
private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
if (shouldBeInLowPersistenceMode()) {
brightnessMode = BRIGHTNESS_MODE_LOW_PERSISTENCE;
} else if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
brightnessMode = mLastBrightnessMode;
}
if (!mInitialized || color != mColor || mode != mMode || onMS != mOnMS ||
offMS != mOffMS || mBrightnessMode != brightnessMode) {
if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#"
+ Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
mInitialized = true;
mLastColor = mColor;
mColor = color;
mMode = mode;
mOnMS = onMS;
mOffMS = offMS;
mBrightnessMode = brightnessMode;
Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x"
+ Integer.toHexString(color) + ")");
try {
//调用native方法,通过jni往HAL调用
setLight_native(mId, color, mode, onMS, offMS, brightnessMode);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
}
到这里可以看到,Android 10有两种设置屏幕亮度的方式
方式1:LightsService->SF->HWL HAL->设备节点->背光驱动
方式2:LightsService->Light HAL->设备节点->背光驱动
Android 10 走方式1;Android 9 走方式2
frameworks\base\core\java\android\view\SurfaceControl.java
public static boolean setDisplayBrightness(IBinder displayToken, float brightness) {
...
return nativeSetDisplayBrightness(displayToken, brightness);//调用本地方法
}
frameworks\base\core\jni\android_view_SurfaceControl.cpp
static jboolean nativeSetDisplayBrightness(JNIEnv* env, jclass clazz, jobject displayTokenObject,
jfloat brightness) {
...
status_t error = SurfaceComposerClient::setDisplayBrightness(displayToken, brightness);
return error == OK ? JNI_TRUE : JNI_FALSE;
}
frameworks\native\libs\gui\SurfaceComposerClient.cpp
status_t SurfaceComposerClient::setDisplayBrightness(const sp<IBinder>& displayToken,
float brightness) {
return ComposerService::getComposerService()->setDisplayBrightness(displayToken, brightness);
}
frameworks\native\services\surfaceflinger\SurfaceFlinger.cpp
status_t SurfaceFlinger::setDisplayBrightness(const sp<IBinder>& displayToken,
float brightness) const {
...
return getHwComposer().setDisplayBrightness(*displayId, brightness);
}
frameworks\native\services\surfaceflinger\DisplayHardware\ComposerHal.cpp
Error Composer::setDisplayBrightness(Display display, float brightness) {
if (!mClient_2_3) {
return Error::UNSUPPORTED;
}
return mClient_2_3->setDisplayBrightness(display, brightness);
}
hardware\qcom\display\sdm\libs\hwc2\hwc_session_services.cpp
int32_t HWCSession::setDisplayBrightness(uint32_t display, float brightness) {
return SetDisplayBrightness(static_cast<hwc2_device_t *>(this),
static_cast<hwc2_display_t>(display), brightness);
}
hardware\qcom\display\sdm\libs\hwc2\hwc_session.cpp
int32_t HWCSession::SetDisplayBrightness(hwc2_device_t *device, hwc2_display_t display,
float brightness) {
...
HWCSession *hwc_session = static_cast<HWCSession *>(device);
HWCDisplay *hwc_display = hwc_session->hwc_display_[display];
if (!hwc_display) {
return HWC2_ERROR_BAD_PARAMETER;
}
return INT32(hwc_display->SetPanelBrightness(brightness));
}
hardware\qcom\display\sdm\libs\hwc2\hwc_display_builtin.cpp
HWC2::Error HWCDisplayBuiltIn::SetPanelBrightness(float brightness) {
DisplayError ret = display_intf_->SetPanelBrightness(brightness);
...
}
DisplayInterface接口SetPanelBrightness()最终在display_builtin.cpp中实现
hardware\qcom\display\sdm\libs\core\display_builtin.cpp
DisplayError DisplayBuiltIn::SetPanelBrightness(float brightness) {
...
DisplayError err = kErrorNone;
if ((err = hw_intf_->SetPanelBrightness(level)) == kErrorNone) {
DLOGI_IF(kTagDisplay, "Setting brightness to level %d (%f percent)", level,
brightness * 100);
}
return err;
}
hardware\qcom\display\sdm\libs\core\drm\hw_peripheral_drm.cpp
DisplayError HWPeripheralDRM::SetPanelBrightness(int level) {
char buffer[kMaxSysfsCommandLength] = {0};
if (brightness_base_path_.empty()) {
return kErrorHardware;
}
std::string brightness_node(brightness_base_path_ + "brightness");
int fd = Sys::open_(brightness_node.c_str(), O_RDWR);
...
int32_t bytes = snprintf(buffer, kMaxSysfsCommandLength, "%d\n", level);
ssize_t ret = Sys::pwrite_(fd, buffer, static_cast<size_t>(bytes), 0);//向背光文件节点brightness_base_path_ 写入数据,brightness_base_path_ 是在GetHWPanelMaxBrightness()获取最大屏亮度值设置的
...
}
void HWPeripheralDRM::GetHWPanelMaxBrightness() {
char value[kMaxStringLength] = {0};
hw_panel_info_.panel_max_brightness = 255.0f;
char s[kMaxStringLength] = {};
snprintf(s, sizeof(s), "/sys/class/backlight/panel%d-backlight/",
static_cast<int>(connector_info_.type_id - 1));
brightness_base_path_.assign(s);//设置亮度文件节点
std::string brightness_node(brightness_base_path_ + "max_brightness");
int fd = Sys::open_(brightness_node.c_str(), O_RDONLY);
...
}
后续流程则是驱动读写设备节点,到这里我们可以通过adb查看display的设备节点,并读取亮度值
#查看backlight设备节点
> adb shell ls -al sys/class/backlight
total 0
drwxr-xr-x 2 root root 0 1970-01-07 07:53 .
drwxr-xr-x 92 root root 0 1970-01-07 07:53 ..
lrwxrwxrwx 1 root root 0 1970-01-07 07:53 panel0-backlight -> ../../devices/platform/soc/5e00000.qcom,mdss_mdp/backlight/panel0-backlight
#查看屏背光节点文件
> adb shell ls -al sys/class/backlight/panel0-backlight/
total 0
drwxr-xr-x 3 root root 0 1970-01-07 07:53 .
drwxr-xr-x 3 root root 0 1970-01-07 07:53 ..
-r--r--r-- 1 root root 4096 1970-01-07 07:53 actual_brightness
-rw-r--r-- 1 root root 4096 1970-01-07 07:53 bl_power
-rw-r--r-- 1 system system 4096 1970-01-07 07:53 brightness
lrwxrwxrwx 1 root root 0 1970-01-07 07:53 device -> ../../../5e00000.qcom,mdss_mdp
-r--r--r-- 1 system system 4096 1970-01-07 07:53 max_brightness
drwxr-xr-x 2 root root 0 1970-01-07 07:53 power
lrwxrwxrwx 1 root root 0 1970-01-07 07:53 subsystem -> ../../../../../../class/backlight
-r--r--r-- 1 root root 4096 1970-01-07 07:53 type
-rw-r--r-- 1 root root 4096 1970-01-07 07:53 uevent
#读取屏亮度
> adb shell cat sys/class/backlight/panel0-backlight/brightness
102
1.4、点亮屏幕
到这里屏幕默认亮度数据从framework经过hal写入了设备节点文件中,但亮屏还未亮起。具体流程如下:
PowerManagerService(PMS)在执行完构造方法、onStart()、OnBootPhase()后由SystemServer调用的systemReady()。
frameworks\base\services\java\com\android\server\SystemServer.java
traceBeginAndSlog("MakePowerManagerServiceReady");
try {
// TODO: use boot phase
mPowerManagerService.systemReady(mActivityManagerService.getAppOpsService());
} catch (Throwable e) {
reportWtf("making Power Manager Service ready", e);
}
traceEnd();
frameworks\base\services\core\java\com\android\server\power\PowerManagerService.java
public void systemReady(IAppOpsService appOps) {
synchronized (mLock) {
mSystemReady = true;
mAppOps = appOps;
//获取各类本地和远程服务用于交互,如屏保DreamManager、电源BatteryStatsService、传感器SensorManager等。
mDreamManager = getLocalService(DreamManagerInternal.class);
mDisplayManagerInternal = getLocalService(DisplayManagerInternal.class);
mPolicy = getLocalService(WindowManagerPolicy.class);
mBatteryManagerInternal = getLocalService(BatteryManagerInternal.class);
mAttentionDetector.systemReady(mContext);
PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
mScreenBrightnessSettingMinimum = pm.getMinimumScreenBrightnessSetting();
mScreenBrightnessSettingMaximum = pm.getMaximumScreenBrightnessSetting();
mScreenBrightnessSettingDefault = pm.getDefaultScreenBrightnessSetting();
SensorManager sensorManager = new SystemSensorManager(mContext, mHandler.getLooper());
// The notifier runs on the system server's main looper so as not to interfere
// with the animations and other critical functions of the power manager.
mBatteryStats = BatteryStatsService.getService();
mNotifier = mInjector.createNotifier(Looper.getMainLooper(), mContext, mBatteryStats,
mInjector.createSuspendBlocker(this, "PowerManagerService.Broadcasts"),
mPolicy);
mWirelessChargerDetector = mInjector.createWirelessChargerDetector(sensorManager,
mInjector.createSuspendBlocker(
this, "PowerManagerService.WirelessChargerDetector"),
mHandler);
mSettingsObserver = new SettingsObserver(mHandler);
mLightsManager = getLocalService(LightsManager.class);
mAttentionLight = mLightsManager.getLight(LightsManager.LIGHT_ID_ATTENTION);
//初始化显示器电源管理,initPowerManagement()中实例化DPC(DisplayPowerController)
// Initialize display power management.
mDisplayManagerInternal.initPowerManagement(
mDisplayPowerCallbacks, mHandler, sensorManager);
try {
final ForegroundProfileObserver observer = new ForegroundProfileObserver();
ActivityManager.getService().registerUserSwitchObserver(observer, TAG);
} catch (RemoteException e) {
// Shouldn't happen since in-process.
}
// Go.
readConfigurationLocked();//读取配置文件默认值
updateSettingsLocked();//更新Settings值
mDirty |= DIRTY_BATTERY_STATE;
updatePowerStateLocked();//更新电源状态
}
final ContentResolver resolver = mContext.getContentResolver();
mConstants.start(resolver);
mBatterySaverController.systemReady();
mBatterySaverPolicy.systemReady();
//注册SettingsObserver监听
// Register for settings changes.
resolver.registerContentObserver(Settings.Secure.getUriFor(
Settings.Secure.SCREENSAVER_ENABLED),
false, mSettingsObserver, UserHandle.USER_ALL);
...
//注册用于和其他System交互的广播
// Register for broadcasts from other components of the system.
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
mContext.registerReceiver(new BatteryReceiver(), filter, null, mHandler);
...
}
private void updatePowerStateLocked() {
...
// Phase 3: Update display power state.更显显示器电源状态,确认显示器是否准备好
final boolean displayBecameReady = updateDisplayPowerStateLocked(dirtyPhase2);
...
} finally {
Trace.traceEnd(Trace.TRACE_TAG_POWER);
}
}
private boolean updateDisplayPowerStateLocked(int dirty) {
...
mDisplayReady = mDisplayManagerInternal.requestPowerState(mDisplayPowerRequest,
mRequestWaitForNegativeProximity);
mRequestWaitForNegativeProximity = false;
if ((dirty & DIRTY_QUIESCENT) != 0) {
sQuiescent = false;
}
...
}
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java
@Override
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mSyncRoot) {
return mDisplayPowerController.requestPowerState(request,
waitForNegativeProximity);
}
}
frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java
public boolean requestPowerState(DisplayPowerRequest request,
boolean waitForNegativeProximity) {
synchronized (mLock) {
...
if (changed && !mPendingRequestChangedLocked) {
mPendingRequestChangedLocked = true;
sendUpdatePowerStateLocked();//发送消息更新电源状态
}
return mDisplayReadyLocked;
}
}
private void sendUpdatePowerStateLocked() {
if (!mPendingUpdatePowerStateLocked) {
mPendingUpdatePowerStateLocked = true;
Message msg = mHandler.obtainMessage(MSG_UPDATE_POWER_STATE);//发送MSG_UPDATE_POWER_STATE消息
mHandler.sendMessage(msg);
}
}
private final class DisplayControllerHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_UPDATE_POWER_STATE:
updatePowerState();
break;
...
}
private void updatePowerState() {
//当DisplayPowerController中更新屏幕状态成功后是否必须通知PMS
final boolean mustNotify;
boolean mustInitialize = false;
//是否自动调节亮度调节值改变
boolean autoBrightnessAdjustmentChanged = false;
synchronized (mLock) {
mPendingUpdatePowerStateLocked = false;
if (mPendingRequestLocked == null) {
return; // wait until first actual power request
}
if (mPowerRequest == null) {
mPowerRequest = new DisplayPowerRequest(mPendingRequestLocked);
mWaitingForNegativeProximity =
mPendingWaitForNegativeProximityLocked;
mPendingWaitForNegativeProximityLocked = false;
mPendingRequestChangedLocked = false;
mustInitialize = true;
} else if (mPendingRequestChangedLocked) {
//自动调节亮度值是否改变,由"当前电源的请求状态"和"将要请求的电源请求状态"比较
autoBrightnessAdjustmentChanged =
(mPowerRequest.screenAutoBrightnessAdjustment
!= mPendingRequestLocked.screenAutoBrightnessAdjustment);
...
}
mustNotify = !mDisplayReadyLocked;
}
if (mustInitialize) {
//初始化亮灭屏动画、mPowerState等
initialize();
}
int state;
int brightness = PowerManager.BRIGHTNESS_DEFAULT;
boolean performScreenOffTransition = false;
//根据PMS中的请求参数决定屏幕状态和屏幕亮度值
switch (mPowerRequest.policy) {
//灭屏
case DisplayPowerRequest.POLICY_OFF:
...
//Doze模式
case DisplayPowerRequest.POLICY_DOZE:
...
//VR模式
case DisplayPowerRequest.POLICY_VR:
...
//DIM和亮屏
case DisplayPowerRequest.POLICY_DIM:
case DisplayPowerRequest.POLICY_BRIGHT:
default:
state = Display.STATE_ON;
break;
}
assert(state != Display.STATE_UNKNOWN);
...
//获取屏幕状态,此时还未设置新的屏幕状态,因此是”旧”的
final int oldState = mPowerState.getScreenState();
//在这个方法中会进行屏幕状态、亮度的设置和处理亮灭屏动画
animateScreenStateChange(state, performScreenOffTransition);
state = mPowerState.getScreenState();
// Use zero brightness when screen is off.
//如果屏幕状态为灭屏,设置亮度为0
if (state == Display.STATE_OFF) {
brightness = PowerManager.BRIGHTNESS_OFF;
}
...
//亮度调节值计算 BEG
//brightnessboost相关
if (mPowerRequest.boostScreenBrightness
&& brightness != PowerManager.BRIGHTNESS_OFF) {
brightness = PowerManager.BRIGHTNESS_ON;
}
// Apply auto-brightness.
boolean slowChange = false;
//如果brightness=PowerManager.BRIGHTNESS_DEFAULT=-1,说明请求屏幕状态非Off
if (brightness < 0) {//default = -1
//如果自动调节亮度可用
if (autoBrightnessEnabled) {
//从AutomaticBrightnessController中获取自动调节亮度值
brightness =
mAutomaticBrightnessController.getAutomaticScreenBrightness();
}
if (brightness >= 0) {//说明使用了自动亮度
// Use current auto-brightness value and slowly adjust to changes.
//调整brightness保持在最小值和最大值之间
//即mScreenBrightnessRangeMinimum <= brightness <= mScreenBrightnessRangeMaximum
brightness = clampScreenBrightness(brightness);
if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
slowChange = true; // slowly adapt to auto-brightness
}
mAppliedAutoBrightness = true;//表示使用自动亮度
} else {
mAppliedAutoBrightness = false;
}
} else {
mAppliedAutoBrightness = false;
}
//如果PMS中请求的屏幕状态为Doze,则将亮度设置为Doze状态的亮度
if (brightness < 0 && (state == Display.STATE_DOZE
|| state == Display.STATE_DOZE_SUSPEND)) {
brightness = mScreenBrightnessDozeConfig;
}
//如果此时brightness还为-1,说明没有使用自动调节亮度和doze状态亮度,则使用手动设置亮度
if (brightness < 0) {
//获取screenBrightness并在取值区间进行判断
brightness = clampScreenBrightness(mPowerRequest.screenBrightness);
}
// Apply dimming by at least some minimum amount when user activity
// timeout is about to expire.
//如果PMS中请求屏幕状态为Dim状态,则使用dim状态时的亮度,基于手动调节值
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
if (brightness > mScreenBrightnessRangeMinimum) {
brightness = Math.max(Math.min(brightness -
SCREEN_DIM_MINIMUM_REDUCTION,
mScreenBrightnessDimConfig),
mScreenBrightnessRangeMinimum);
}
if (!mAppliedDimming) {
slowChange = false;
}
mAppliedDimming = true;//表示采用Dim状态brightness
} else if (mAppliedDimming) {
slowChange = false;
mAppliedDimming = false;
}
...
//亮度动画
if (!mPendingScreenOff) {
//是否在亮屏时跳过亮度坡度调节,默认false
if (mSkipScreenOnBrightnessRamp) {
//如果屏幕状态为亮屏状态
if (state == Display.STATE_ON) {
if (mSkipRampState == RAMP_STATE_SKIP_NONE && mDozing) {
mInitialAutoBrightness = brightness;
mSkipRampState = RAMP_STATE_SKIP_INITIAL;
} else if (mSkipRampState == RAMP_STATE_SKIP_INITIAL
&& mUseSoftwareAutoBrightnessConfig
&& brightness != mInitialAutoBrightness) {
mSkipRampState = RAMP_STATE_SKIP_AUTOBRIGHT;
} else if (mSkipRampState == RAMP_STATE_SKIP_AUTOBRIGHT) {
mSkipRampState = RAMP_STATE_SKIP_NONE;
}
} else {
mSkipRampState = RAMP_STATE_SKIP_NONE;
}
}
//是否处于或将要进入VR状态
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) {
//设置亮度,slowChange=true应用于自动调节亮度
animateScreenBrightness(brightness,
slowChange ? mBrightnessRampRateSlow :
mBrightnessRampRateFast);
} else {
//其他情况下不适用亮度动画,直接设置亮度
animateScreenBrightness(brightness, 0);
}
}
...
}
总结一下,在updatePowerState()中:
- 初始化相关变量
- 调用animateScreenState()方法设置屏幕状态
- 更新显示设备状态
- 计算屏幕亮度值
- 调用animateScreenBrightness()设置亮度动画
//1、initialize()初始化亮度调节动画
private void initialize() {
// Initialize the power state object for the default display.
// In the future, we might manage multiple displays independently.
mPowerState = new DisplayPowerState(mBlanker,
mColorFadeEnabled ? new ColorFade(Display.DEFAULT_DISPLAY) : null);
if (mColorFadeEnabled) {
//设置亮屏亮度动画
mColorFadeOnAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f);
mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS);
mColorFadeOnAnimator.addListener(mAnimatorListener);
//设置熄屏亮度动画
mColorFadeOffAnimator = ObjectAnimator.ofFloat(
mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
mColorFadeOffAnimator.addListener(mAnimatorListener);
}
...
// Initialize all of the brightness tracking state
final float brightness = convertToNits(mPowerState.getScreenBrightness());
if (brightness >= 0.0f) {
mBrightnessTracker.start(brightness);
}
...
}
//2、
private void animateScreenStateChange(int target, boolean performScreenOffTransition) {
// If there is already an animation in progress, don't interfere with it.
//亮度调节动画还未结束
if (mColorFadeEnabled &&
(mColorFadeOnAnimator.isStarted() || mColorFadeOffAnimator.isStarted())) {
if (target != Display.STATE_ON) {
return;
}
// If display state changed to on, proceed and stop the color fade and turn screen on.
mPendingScreenOff = false;
}
...
//执行亮屏动画
if (USE_COLOR_FADE_ON_ANIMATION && mColorFadeEnabled && mPowerRequest.isBrightOrDim()) {
// Perform screen on animation.
if (mPowerState.getColorFadeLevel() == 1.0f) {
mPowerState.dismissColorFade();
} else if (mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ?
ColorFade.MODE_FADE :
ColorFade.MODE_WARM_UP)) {
mColorFadeOnAnimator.start();
} else {
mColorFadeOnAnimator.end();
}
} else {
// Skip screen on animation.
//跳过亮屏动画
mPowerState.setColorFadeLevel(1.0f);
mPowerState.dismissColorFade();
}
} else if (target == Display.STATE_VR) {
// Wait for brightness animation to complete beforehand when entering VR
// from screen on to prevent a perceptible jump because brightness may operate
// differently when the display is configured for dozing.
if (mScreenBrightnessRampAnimator.isAnimating()
&& mPowerState.getScreenState() == Display.STATE_ON) {
return;
}
...
if (mPowerState.getColorFadeLevel() == 0.0f) {
// Turn the screen off.
// A black surface is already hiding the contents of the screen.
setScreenState(Display.STATE_OFF);
mPendingScreenOff = false;
mPowerState.dismissColorFadeResources();
} else if (performScreenOffTransition
&& mPowerState.prepareColorFade(mContext,
mColorFadeFadesConfig ?
ColorFade.MODE_FADE : ColorFade.MODE_COOL_DOWN)
&& mPowerState.getScreenState() != Display.STATE_OFF) {
// Perform the screen off animation.执行熄屏动画
mColorFadeOffAnimator.start();
} else {
// Skip the screen off animation and add a black surface to hide the
// contents of the screen.
//跳过熄屏动画,直接灭屏
mColorFadeOffAnimator.end();
}
}
}
//设置亮度动画目标值
private void animateScreenBrightness(int target, int rate) {
if (DEBUG) {
Slog.d(TAG, "Animating brightness: target=" + target +", rate=" + rate);
}
if (mScreenBrightnessRampAnimator.animateTo(target, rate)) {
Trace.traceCounter(Trace.TRACE_TAG_POWER, "TargetScreenBrightness", target);
try {
mBatteryStats.noteScreenBrightness(target);
} catch (RemoteException ex) {
// same process
}
}
}
二、关机熄屏流程
从开机流程图中可以一瞥熄屏流程
同亮屏一样,在DPC updatePowerState()中设置熄屏亮度动画、更新熄屏状态和设置亮度值。
frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java
private boolean setScreenState(int state) {
return setScreenState(state, false /*reportOnly*/);
}
private boolean setScreenState(int state, boolean reportOnly) {
final boolean isOff = (state == Display.STATE_OFF);
if (mPowerState.getScreenState() != state) {
// If we are trying to turn screen off, give policy a chance to do something before we
// actually turn the screen off.
if (isOff && !mScreenOffBecauseOfProximity) {
if (mReportedScreenStateToPolicy == REPORTED_TO_POLICY_SCREEN_ON) {
setReportedScreenState(REPORTED_TO_POLICY_SCREEN_TURNING_OFF);
blockScreenOff();
mWindowManagerPolicy.screenTurningOff(mPendingScreenOffUnblocker);//PMS进行关机流程
unblockScreenOff();
} else if (mPendingScreenOffUnblocker != null) {
// Abort doing the state change until screen off is unblocked.
return false;
}
}
...
// Return true if the screen isn't blocked.
return mPendingScreenOnUnblocker == null;
}
frameworks\base\services\core\java\com\android\server\policy\PhoneWindowManager.java
@Override
public void screenTurningOff(ScreenOffListener screenOffListener) {
mWindowManagerFuncs.screenTurningOff(screenOffListener);
synchronized (mLock) {
if (mKeyguardDelegate != null) {
mKeyguardDelegate.onScreenTurningOff();
}
}
}
三、自动亮度调节
设计代码及其路径如下:
frameworks\base\core\res\res\values\config.xml
frameworks\base\core\java\android\os\PowerManager.java
frameworks\base\packages\SystemUI\src\com\android\systemui\settings\BrightnessDialog.java
frameworks\base\packages\SystemUI\src\com\android\systemui\settings\BrightnessController.java
frameworks\base\services\core\java\com\android\server\display\BrightnessMappingStrategy.java
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java
frameworks\base\services\core\java\com\android\server\display\AutomaticBrightnessController.java
在本小节通过调节系统设置亮度,分析系统是如何进行亮度自动调节的,代码时序图如下:
在梳理亮度自动调节流程之前有必要先介绍点基本概念:
- 环境光:表示真实环境的光亮度值,即照度,单位为lux。
- Nit值:即尼特,表示人肉眼感知的光强度的单位。
- 屏幕背光:即灰阶,范围0~255,由上层设置到驱动,并最终音效屏幕亮度的值。
- 屏幕亮度:即屏幕的真实亮度。
从系统设置中调节亮度出发
frameworks\base\packages\SystemUI\src\com\android\systemui\settings\BrightnessDialog.java
//在系统设置中点击亮度调节选项后,启用SystemUI的BrightnessDialog.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
final ToggleSliderView slider = findViewById(R.id.brightness_slider);
mBrightnessController = new BrightnessController(this, slider);//实例化亮度控制器BrightnessController
}
frameworks\base\packages\SystemUI\src\com\android\systemui\settings\BrightnessController.java
public BrightnessController(Context context, ToggleSlider control) {
mContext = context;
mControl = control;
mControl.setMax(GAMMA_SPACE_MAX);
mBackgroundHandler = new Handler((Looper) Dependency.get(Dependency.BG_LOOPER));
mUserTracker = new CurrentUserTracker(mContext) {
@Override
public void onUserSwitched(int newUserId) {
mBackgroundHandler.post(mUpdateModeRunnable);
mBackgroundHandler.post(mUpdateSliderRunnable);
}
};
mBrightnessObserver = new BrightnessObserver(mHandler);//实例化mBrightnessObserver
PowerManager pm = context.getSystemService(PowerManager.class);
//从配置文件中获取亮度最大255、最小0、默认值102、自动亮度开关等数据
mMinimumBacklight = pm.getMinimumScreenBrightnessSetting();
mMaximumBacklight = pm.getMaximumScreenBrightnessSetting();
mDefaultBacklight = pm.getDefaultScreenBrightnessSetting();
mMinimumBacklightForVr = pm.getMinimumScreenBrightnessForVrSetting();
mMaximumBacklightForVr = pm.getMaximumScreenBrightnessForVrSetting();
mDefaultBacklightForVr = pm.getDefaultScreenBrightnessForVrSetting();
mAutomaticAvailable = context.getResources().getBoolean(
com.android.internal.R.bool.config_automatic_brightness_available);
mDisplayManager = context.getSystemService(DisplayManager.class);
mVrManager = IVrManager.Stub.asInterface(ServiceManager.getService(
Context.VR_SERVICE));
}
//通过线程异步更新滑动UI
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
mExternalChange = true;
try {
switch (msg.what) {
case MSG_UPDATE_SLIDER:
updateSlider(msg.arg1, msg.arg2 != 0);
break;
...
}
};
private void updateSlider(int val, boolean inVrMode) {
final int min;
final int max;
if (inVrMode) {
min = mMinimumBacklightForVr;
max = mMaximumBacklightForVr;
} else {
min = mMinimumBacklight;
max = mMaximumBacklight;
}
if (val == convertGammaToLinear(mControl.getValue(), min, max)) {
// If we have more resolution on the slider than we do in the actual setting, then
// multiple slider positions will map to the same setting value. Thus, if we see a
// setting value here that maps to the current slider position, we don't bother to
// calculate the new slider position since it may differ and look like a brightness
// change to the user even though it isn't one.
return;
}
final int sliderVal = convertLinearToGamma(val, min, max);//Gamma线性变化为亮度百分比值
animateSliderTo(sliderVal);//动画更新UI亮度值
}
private void animateSliderTo(int target) {
...
mSliderAnimator = ValueAnimator.ofInt(mControl.getValue(), target);
mSliderAnimator.addUpdateListener((ValueAnimator animation) -> {
mExternalChange = true;
mControl.setValue((int) animation.getAnimatedValue());
mExternalChange = false;
});
final long animationDuration = SLIDER_ANIMATION_DURATION * Math.abs(
mControl.getValue() - target) / GAMMA_SPACE_MAX;
mSliderAnimator.setDuration(animationDuration);
mSliderAnimator.start();
}
@Override
public void onChanged(ToggleSlider toggleSlider, boolean tracking, boolean automatic,
int value, boolean stopTracking) {
...
final int val = convertGammaToLinear(value, min, max);//将百分比电量值Gamma线性转换
...
setBrightness(val);
...
}
private void setBrightness(int brightness) {
mDisplayManager.setTemporaryBrightness(brightness);
}
frameworks\base\services\core\java\com\android\server\display\DisplayManagerService.java
@Override // Binder call
public void setTemporaryBrightness(int brightness) {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.CONTROL_DISPLAY_BRIGHTNESS,
"Permission required to set the display's brightness");
final long token = Binder.clearCallingIdentity();
try {
synchronized (mSyncRoot) {
mDisplayPowerController.setTemporaryBrightness(brightness);
}
} finally {
Binder.restoreCallingIdentity(token);
}
}
frameworks\base\services\core\java\com\android\server\display\DisplayPowerController.java
public void setTemporaryBrightness(int brightness) {
Message msg = mHandler.obtainMessage(MSG_SET_TEMPORARY_BRIGHTNESS,
brightness, 0 /*unused*/);
msg.sendToTarget();
}
private final class DisplayControllerHandler extends Handler {
public DisplayControllerHandler(Looper looper) {
super(looper, null, true /*async*/);
}
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
...
case MSG_SET_TEMPORARY_BRIGHTNESS:
// TODO: Should we have a a timeout for the temporary brightness?
mTemporaryScreenBrightness = msg.arg1;//保存临时亮度值
updatePowerState();
break;
private void updatePowerState() {
...
// Configure auto-brightness.
if (mAutomaticBrightnessController != null) {
hadUserBrightnessPoint = mAutomaticBrightnessController.hasUserDataPoints();
//1、对自动亮度调节控制器进行配置
mAutomaticBrightnessController.configure(autoBrightnessEnabled,
mBrightnessConfiguration,
mLastUserSetScreenBrightness / (float) PowerManager.BRIGHTNESS_ON,
userSetBrightnessChanged, autoBrightnessAdjustment,
autoBrightnessAdjustmentChanged, mPowerRequest.policy);
}
if (brightness < 0) {//default = -1
//如果自动调节亮度可用
if (autoBrightnessEnabled) {
//2、从AutomaticBrightnessController中获取自动调节亮度值
brightness =
mAutomaticBrightnessController.getAutomaticScreenBrightness();
}
if (brightness >= 0) {//说明使用了自动亮度
brightness = clampScreenBrightness(brightness);
if (mAppliedAutoBrightness && !autoBrightnessAdjustmentChanged) {
slowChange = true; // slowly adapt to auto-brightness
}
mAppliedAutoBrightness = true;//表示使用自动亮度
} else {
mAppliedAutoBrightness = false;
}
} else {
mAppliedAutoBrightness = false;
}
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_DIM) {
if (brightness > mScreenBrightnessRangeMinimum) {
brightness = Math.max(Math.min(brightness -
SCREEN_DIM_MINIMUM_REDUCTION,
mScreenBrightnessDimConfig),
mScreenBrightnessRangeMinimum);
}
if (!mAppliedDimming) {
slowChange = false;
}
mAppliedDimming = true;//表示采用Dim状态brightness
} else if (mAppliedDimming) {
slowChange = false;
mAppliedDimming = false;
}
...
//设置亮度,slowChange=true应用于自动调节亮度
animateScreenBrightness(brightness,
slowChange ? mBrightnessRampRateSlow :
mBrightnessRampRateFast);
} else {
//其他情况下不适用亮度动画,直接设置亮度
animateScreenBrightness(brightness, 0);
}
}
...
}
frameworks\base\services\core\java\com\android\server\display\AutomaticBrightnessController.java
//1、配置AutomaticBrightnessController自动亮度调节控制器
public void configure(boolean enable, @Nullable BrightnessConfiguration configuration,
float brightness, boolean userChangedBrightness, float adjustment,
boolean userChangedAutoBrightnessAdjustment, int displayPolicy) {
...
//自动亮度值发生变化
if (userInitiatedChange && enable && !dozing) {
prepareBrightnessAdjustmentSample();
}
//注册/解除注册LightSensor,即开启自动调节亮度且非Doze状态下才可用
changed |= setLightSensorEnabled(enable && !dozing);
//调整自动亮度值
if (changed) {
updateAutoBrightness(false /*sendUpdate*/, userInitiatedChange);
}
}
//更新自动亮度
private void updateAutoBrightness(boolean sendUpdate, boolean isManuallySet) {
if (!mAmbientLuxValid) {//光照强度值是否有效
return;
}
//根据当前环境光照值从曲线中获取亮度值,并转成0~255内int值newScreenAutoBrightness
//mAmbientLux由光照传感器监听光照发送变化时更新
float value = mBrightnessMapper.getBrightness(mAmbientLux, mForegroundAppPackageName,
mForegroundAppCategory);
int newScreenAutoBrightness = Math.round(clampScreenBrightness(
value * PowerManager.BRIGHTNESS_ON));
...
if (mScreenAutoBrightness != newScreenAutoBrightness) {
if (mLoggingEnabled) {
Slog.d(TAG, "updateAutoBrightness: " +
"mScreenAutoBrightness=" + mScreenAutoBrightness + ", " +
"newScreenAutoBrightness=" + newScreenAutoBrightness);
}
mScreenAutoBrightness = newScreenAutoBrightness;//将最新的亮度值保存至mScreenAutoBrightness
mScreenBrighteningThreshold = clampScreenBrightness(
mScreenBrightnessThresholds.getBrighteningThreshold(newScreenAutoBrightness));
mScreenDarkeningThreshold = clampScreenBrightness(
mScreenBrightnessThresholds.getDarkeningThreshold(newScreenAutoBrightness));
if (sendUpdate) {
mCallbacks.updateBrightness();
}
}
}
//2、获取处理后的自动亮度值
public int getAutomaticScreenBrightness() {
if (!mAmbientLuxValid) {//光照强度值是否有效
return -1;
}
if (mDisplayPolicy == DisplayPowerRequest.POLICY_DOZE) {
return (int) (mScreenAutoBrightness * mDozeScaleFactor);
}
return mScreenAutoBrightness;//返回自动亮度值,而它则是在上面
}
自此,通过LightSensor获取的光照数据–>最终计算出屏幕亮度。,结合config.xml默认的光照-亮度数组进行计算得到新的亮度值,从而实现自动调节屏幕亮度。
上述代码中未展开介绍调光相关的曲线配置:
frameworks\base\core\res\res\values\config.xml
...
<integer-array name="config_autoBrightnessLevels"> //光感[Lux]数组,定义检测到的光照亮度
</integer-array>
<array name="config_autoBrightnessDisplayValuesNits"> // Lux值对应的Nits值数组[DisplayNits]
</array>
<integer-array name="config_screenBrightnessBacklight"> //与发光强度Nits值对应的背光值数组[BL]
</integer-array>
<array name="config_screenBrightnessNits"> //描述屏幕发光强度的[Nit]值数组
</array>
上述数组Android源码默认没有配置,需要根据厂商的实际需要进行定制化配置。
Android系统提供的上述Lux、DisplayNit、BL、Nit四个数组配置曲线,两两分组得到两条曲线:
- Lux - DisplayNit
- Nit -BL
其中DisplayNit与Nit是同一个值,这样光感强度Lux与屏幕背光亮度通过这两条曲线就连接起来了,整体大致过程如下:
1、真实环境光照到设备光传感器
2、光传感器上报感光Lux数据
3、通过Lux - DisplayNit曲线,将Lux转化为了Nit值
4、通过Nit - BL曲线将,Nit转化为背光值
5、为了防止亮度设置过程中闪屏,调用animateScreenBrightness设置亮度动画
Android9.0之前直接是Lux - BL,只有config_autoBrightnessLevels数组,直接将sensor获取的lux转为BL,从9.0 开始引入其他三个配置,这是因为从光学角度而言,人肉眼感知的亮度是从屏幕反射到眼球中的光强度,而这个强度与光亮度Nit有一定关系,Nit又与Lux有关,所以严格考虑到光照度,光亮度,入射光、反射光等调节,相比通过Lux决定BL而言,通过Lux决定Nit,再由Nit决定BL使得亮度更加精准。
四、亮屏、熄屏广播
亮屏和熄屏时Notifier会发送相应的广播
frameworks\base\services\core\java\com\android\server\power\Notifier.java
mScreenOnIntent = new Intent(Intent.ACTION_SCREEN_ON);
mScreenOnIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
mScreenOffIntent = new Intent(Intent.ACTION_SCREEN_OFF);
mScreenOffIntent.addFlags(
Intent.FLAG_RECEIVER_REGISTERED_ONLY | Intent.FLAG_RECEIVER_FOREGROUND
| Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS);
...
private void sendWakeUpBroadcast() {
...
if (mActivityManagerInternal.isSystemReady()) {
//亮屏广播发送完成后最后被mWakeUpBroadcastDone接收
mContext.sendOrderedBroadcastAsUser(mScreenOnIntent, UserHandle.ALL, null,
mWakeUpBroadcastDone, mHandler, 0, null, null);
} else {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 2, 1);
sendNextBroadcast();
}
}
private void sendGoToSleepBroadcast() {
...
if (mActivityManagerInternal.isSystemReady()) {
//熄屏广播发送完成后最后被mWakeUpBroadcastDone接收
mContext.sendOrderedBroadcastAsUser(mScreenOffIntent, UserHandle.ALL, null,
mGoToSleepBroadcastDone, mHandler, 0, null, null);
} else {
EventLog.writeEvent(EventLogTags.POWER_SCREEN_BROADCAST_STOP, 3, 1);
sendNextBroadcast();
}
}
五、总结
在本文中,梳理了开机亮屏流程,熄屏流程,以及在AutoBrightness开启时,亮度调节流程。总结如下:
- 亮屏和熄屏过程并不一定是直接亮的,而是存在亮度动画,逐渐亮屏和熄屏,可能是为了改善使用体验,例如晚上解锁手机屏幕过亮。
- 亮度可以通过abd查看、修改数据库和屏亮度设备节点文件
$ adb shell settings get system screen_brightness
$ adb shell settings put system screen_brightness
$ adb shell cat sys/class/backlight/panelxxx/brightness
$ adb shell echo 255 > sys/class/backlight/panelxxx/brightness
- 亮屏和熄屏系统都会发送对应的广播,可用于在亮屏或熄屏时执行某些动作
Intent.ACTION_SCREEN_ON //亮屏广播
Intent.ACTION_SCREEN_OFF//熄屏广播
- 自动亮度调节原理是通过监听光传感器亮度发送变化时,根据环境的光亮结合可定制的亮度-光亮数组设置屏亮度,从而达到亮度自适应。