前言
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

 @VisibleForTestingDisplayManagerService(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

 @UnsupportedAppUsagepublic 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

 @Overridepublic void onStart() {...synchronized (mSyncRoot) {//1、加载本地持久化数据mPersistentDataStore.loadIfNeeded();loadStableDisplayValuesLocked();}//2、发送MSG_REGISTER_DEFAULT_DISPLAY_ADAPTERS 消息,注册默认display_adaptersmHandler.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*/);}@Overridepublic 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 adapterregisterDisplayAdapterLocked(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

 @Overridepublic 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 {@Overridepublic 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 {...@Overridepublic 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() {@Overridepublic 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

@Overridepublic void setBrightness(int brightness) {setBrightness(brightness, BRIGHTNESS_MODE_USER);}@Overridepublic void setBrightness(int brightness, int brightnessMode) {synchronized (this) {// LOW_PERSISTENCE cannot be manually setif (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 phasemPowerManagerService.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

 @Overridepublic 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 {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case MSG_UPDATE_POWER_STATE:updatePowerState();break;...}private void updatePowerState() {//当DisplayPowerController中更新屏幕状态成功后是否必须通知PMSfinal 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.//如果屏幕状态为灭屏,设置亮度为0if (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,说明请求屏幕状态非Offif (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 <= mScreenBrightnessRangeMaximumbrightness = 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) {//是否在亮屏时跳过亮度坡度调节,默认falseif (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 statefinal 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

    @Overridepublic 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
@Overrideprotected 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) {@Overridepublic 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));}//通过线程异步更新滑动UIprivate final Handler mHandler = new Handler() {@Overridepublic 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();}@Overridepublic 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 callpublic 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*/);}@Overridepublic 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//熄屏广播
  • 自动亮度调节原理是通过监听光传感器亮度发送变化时,根据环境的光亮结合可定制的亮度-光亮数组设置屏亮度,从而达到亮度自适应。

Android 10亮屏、熄屏和自动调光相关推荐

  1. android车机总是自动熄屏,华为Mata20 Pro等Android屏幕常亮/永不熄屏APP:no screen off v 1.16...

    华为Mata20 Pro没有永不息屏选项了,但有些专用软件是需要一直运行和查看的,用这软件省去手指隔一段时间点一下屏幕的操作了 虽然刚打开no screen off会弹出的界面说只是针对旧手机有用,提 ...

  2. 计算机控制闪光灯,并联控制式自动调光闪光灯 - 最全的照相机闪光灯电路图大全(十款照相机闪光灯电路图详解)...

    图5所示为并联控制式自动调光闪光灯电路电路中振荡和主闪光灯管的触发闪光与普通闪光灯相似.当主闪光灯管发光后,光敏管VD2 接收到被摄物体反射回来的光,使可控硅VS导通,于是C6储存的电能经T3振荡升压 ...

  3. Android 监听屏幕熄屏亮屏和主动唤醒屏幕

    // 监听熄屏和亮屏需要添加权限 <uses-permission android:name="android.permission.DEVICE_POWER"/> & ...

  4. 【Android】锁屏/熄屏之后,与蓝牙设备的连接就会自动断开

    今天客户给反馈一个比较奇怪的问题,在OPPO Android6.0手机上,锁屏之后,与蓝牙设备的连接就会断开,但是其它手机却没有出现该问题.拿到这个问题一开始也是百思不得其解,但是一个无意中的操作,让 ...

  5. 2022-01-21 界面长亮不熄屏

    1.在AndroidManifest.xml文件中添加权限 <uses-permission android:name="android.permission.WAKE_LOCK&qu ...

  6. Android 点击按钮熄屏

    有时候我们在一些酒店里看到一些控制设备的pad,当我们点击关闭按钮会关闭设备的同时把pad的屏幕给熄灭,我们今天就来尝试实现点击按钮熄灭屏幕这个功能. 1.在res下创建xml文件夹,创建一个lock ...

  7. android 刷机后熄屏断网

    情况说明 我的黑鲨1代刷机后,部署了Linux系统,但是只要熄屏后过一会儿就无法访问网络了.尝试了修改电量管理.关闭省电模式等,均无效. 经过很久很久的测试,终于找到了原因.Android6.0或更高 ...

  8. Android让屏幕保持常亮,不熄屏的三种方法

    转载自https://blog.csdn.net/superxlcr/article/details/78822544 方法一:持有WakeLock 首先获取WakeLock相关权限: <use ...

  9. Android 10.0去除锁屏界面及SystemUI无sim卡拨打紧急电话控件显示

    在开发定制化wifi版平板时,需要去掉所有紧急拨打电话的功能,而紧急拨打电话在锁屏界面 和SystemUI 的下拉快捷里面有这些功能 所以就从这两个地方入手,屏蔽到紧急拨打电话功能 1.SystemU ...

最新文章

  1. xshell问题汇总
  2. avalon $computed不起作用?
  3. AIX卷管理介绍以及利用空闲PP来创建文件系统
  4. SDP协议基本分析(RTSP、WebRTC使用)
  5. pip如何安装到Linux服务器,linux中pip安装步骤与使用详解
  6. Nginx upstream性能优化
  7. Python之面向对象2
  8. 在可部署到brew真机上的程序包构建完之后又要如何将该程序包发布到真机上呢...
  9. 如何防止Eamil发邮件泄露IP地址,隐藏发件人IP教程
  10. netty实战pdf下载,深度解密:Java与线程的关系
  11. 100个优秀安全测试工具
  12. 计算机体检作用,QQ电脑管家什么是电脑体检?有什么作用?
  13. 中国最具竞争力的十大调查研究咨询公司
  14. 状告技术总监,索赔 90 万元,称其拖延研发进度、系统频繁崩溃出错、产品质量存在严重问题...
  15. Linux 之系统美化
  16. 探究:软件工程中的test oracle到底是什么意思?
  17. JavaScript智能填写续写版(QQ邮箱地址栏简化版)
  18. 解决Ubuntu 20.04挂载NTFS分区不能写入(只读权限)的问题
  19. 利用scp 在linux之间传输文件
  20. python中git克隆代码失败_使用Git clone代码失败的解决方法

热门文章

  1. 查询oracle rac状态,RAC常见命令检查状态
  2. 【转】yuv文件显示与测试
  3. 公司注销清算报告内容包括什么
  4. Push推送的评估方法
  5. (超级详细1秒钟秒懂)华为网络初级工程师知识总结(一)
  6. 互联网网站架构演进之 58同城前十年架构演进
  7. 本地AD账户同步到Office 365(21V)Azure AD
  8. 三星s3 android4.4,三星s3怎么刷机?三星i9300刷安卓4.4.2教程
  9. 主持人如何控制知识竞赛抢答赛的赛场
  10. Python-音频补齐(即对不同长度的音频用数据零对齐补位)