Android 10亮屏熄屏和自动调光

Posted Mart!nHu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android 10亮屏熄屏和自动调光相关的知识,希望对你有一定的参考价值。

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

    Android逆向系列文章— Android基础逆向

    本文作者:HAI_

    0×00 前言

    不知所以然,请看

    Android逆向-Android基础逆向(1)

    Android逆向-Android基础逆向(2)

    Android逆向-Android基础逆向(2-2)

    Android逆向-Android基础逆向(2-3补充篇)

    Android逆向-Android基础逆向(3)

    Android逆向-Android基础逆向(4)

    Android逆向-Android基础逆向(4-2)

    Android逆向-Android基础逆向(5)

    以及java系列:

    Android逆向-java代码基础(1)

    Android逆向-java代码基础(2)

    Android逆向-java代码基础(3)

    Android逆向-java代码基础(4)

    Android逆向-java代码基础(5)

    Android逆向-java代码基础(6)

    Android逆向-java代码基础(7)

    Android逆向-java代码基础(8)

    内容or问题

    1.如何写一个登录界面? √
    2.逆向分析登录逻辑 √
    3.如何暴力绕过一个登录界面? √
    4.如何巧妙登录 √
    5..如何加广告√
    6.如何去广告
    7.实例分析

    时间

    2018年2月4日13:10:42

    目的

    1.复习登录界面的书写
    2.暴力练习
    3.获取练习
    4.smali代码熟练
    5.给自己的app加广告
    6.二次打包加广告实战
    7.如何去广告

    0×01 Android 编程—登录界面

    说明

    这个是学编程的时候必须要学的,这次我们就不接数据库来操作。也没有注册界面,直接就是一个简单的登录界面。
    demo还是按照之前的改。恩,反正我会,我就要偷懒。

    1.更改布局

    首先一个用户名的框框。
    1.jpg

    然后一个登录密码的框框。

    2.jpg

    然后还是一个登录按钮

    3.jpg

    预览一下我们的界面

    4.jpg

    好丑,做一个简单的调整,整体代码如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:id="@+id/activity_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        tools:context="com.example.hanlei.first_demo.MainActivity">
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/name"
            android:hint="请输入用户名"
        />
        <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/password"
            android:hint="请输入密码"
            />
        <Button
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/bt"
            android:text="Login"/>
    </LinearLayout>
    

    5.jpg

    2.绑定控件

    恩,为了像一个登录界面,我把name也改了。

    所以重新绑定。

    6.jpg

    3.逻辑书写

      login.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (name.getText().toString().equals("zhuzhu")&&Integer.parseInt(ps.getText().toString())==520)
                    {
                        startActivity(new Intent(MainActivity.this,Main2Activity.class));
                    }
                }
            });

    这里涉及到一个知识点。
    java String 类型如何转换为int类型。
    简单的来说:

    Integer.parseInt();

    就可以转换了
    这里突然想到万一不输入数字怎么办。恩,去改下规范。

     <EditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:id="@+id/password"
            android:inputType="number"
            android:hint="请输入密码"
            />

    这里加了一行只允许输入数字。

    测试

    7.jpg

    0×02 反编译分析

    分析嘛,很多次了。老规矩

    1. Android Killer

    8.jpg

    2.找到主要函数

    我们找到逻辑判断的地方$1

    .class Lcom/example/hanlei/first_demo/MainActivity$1;
    .super Ljava/lang/Object;
    .source "MainActivity.java"
    
    # interfaces
    .implements Landroid/view/View$OnClickListener;
    
    # annotations
    .annotation system Ldalvik/annotation/EnclosingMethod;
        value = Lcom/example/hanlei/first_demo/MainActivity;->onCreate(Landroid/os/Bundle ;) V
    
    .end annotation
    
    .annotation system Ldalvik/annotation/InnerClass;
        accessFlags = 0x0
        name = null
    .end annotation
    
    # instance fields
    .field final synthetic this$0:Lcom/example/hanlei/first_demo/MainActivity;
    
    # direct methods
    .method constructor <init>(Lcom/example/hanlei/first_demo/MainActivity ;) V
    
        .locals 0
        .param p1, "this$0"    # Lcom/example/hanlei/first_demo/MainActivity;
    
        .prologue
        .line 24
        iput-object p1, p0, Lcom/example/hanlei/first_demo/MainActivity$1;->this$0:Lcom/example/hanlei/first_demo/MainActivity;
    
        invoke-direct {p0}, Ljava/lang/Object;-><init>()V
    
        return-void
    .end method
    
    # virtual methods
    .method public onClick(Landroid/view/View ;) V
    
        .locals 4
        .param p1, "v"    # Landroid/view/View;
    
        .prologue
        .line 27
        iget-object v0, p0, Lcom/example/hanlei/first_demo/MainActivity$1;->this$0:Lcom/example/hanlei/first_demo/MainActivity;
    
        # getter for: Lcom/example/hanlei/first_demo/MainActivity;->name:Landroid/widget/EditText;
        invoke-static {v0}, Lcom/example/hanlei/first_demo/MainActivity;->access$000(Lcom/example/hanlei/first_demo/MainActivity ;) Landroid/widget/EditText
    ;
    
        move-result-object v0
    
        invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
    
        move-result-object v0
    
        invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
    
        move-result-object v0
    
        const-string v1, "zhuzhu"
    
        invoke-virtual {v0, v1}, Ljava/lang/String;->equals(Ljava/lang/Object ;) Z
    
    
        move-result v0
    
        if-eqz v0, :cond_0
    
        iget-object v0, p0, Lcom/example/hanlei/first_demo/MainActivity$1;->this$0:Lcom/example/hanlei/first_demo/MainActivity;
    
        # getter for: Lcom/example/hanlei/first_demo/MainActivity;->ps:Landroid/widget/EditText;
        invoke-static {v0}, Lcom/example/hanlei/first_demo/MainActivity;->access$100(Lcom/example/hanlei/first_demo/MainActivity ;) Landroid/widget/EditText
    ;
    
        move-result-object v0
    
        invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
    
        move-result-object v0
    
        invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
    
        move-result-object v0
    
        invoke-static {v0}, Ljava/lang/Integer;->parseInt(Ljava/lang/String ;) I
    
    
        move-result v0
    
        const/16 v1, 0x208
    
        if-ne v0, v1, :cond_0
    
        .line 29
        iget-object v0, p0, Lcom/example/hanlei/first_demo/MainActivity$1;->this$0:Lcom/example/hanlei/first_demo/MainActivity;
    
        new-instance v1, Landroid/content/Intent;
    
        iget-object v2, p0, Lcom/example/hanlei/first_demo/MainActivity$1;->this$0:Lcom/example/hanlei/first_demo/MainActivity;
    
        const-class v3, Lcom/example/hanlei/first_demo/Main2Activity;
    
        invoke-direct {v1, v2, v3}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class ;) V
    
    
        invoke-virtual {v0, v1}, Lcom/example/hanlei/first_demo/MainActivity;->startActivity(Landroid/content/Intent ;) V
    
    
        .line 31
        :cond_0
        return-void
    .end method
    

    3.重点逻辑部分

    重点逻辑就是如何判断登录的部分

    if-eqz v0, :cond_0
    
        iget-object v0, p0, Lcom/example/hanlei/first_demo/MainActivity$1;->this$0:Lcom/example/hanlei/first_demo/MainActivity;
    
        # getter for: Lcom/example/hanlei/first_demo/MainActivity;->ps:Landroid/widget/EditText;
        invoke-static {v0}, Lcom/example/hanlei/first_demo/MainActivity;->access$100(Lcom/example/hanlei/first_demo/MainActivity ;) Landroid/widget/EditText
    ;
    
        move-result-object v0
    
        invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/Editable;
    
        move-result-object v0
    
        invoke-virtual {v0}, Ljava/lang/Object;->toString()Ljava/lang/String;
    
        move-result-object v0
    
        invoke-static {v0}, Ljava/lang/Integer;->parseInt(Ljava/lang/String ;) I
    
    
        move-result v0
    
        const/16 v1, 0x208
    
        if-ne v0, v1, :cond_0
    
        .line 29
        iget-object v0, p0, Lcom/example/hanlei/first_demo/MainActivity$1;->this$0:Lcom/example/hanlei/first_demo/MainActivity;
    
        new-instance v1, Landroid/content/Intent;
    
        iget-object v2, p0, Lcom/example/hanlei/first_demo/MainActivity$1;->this$0:Lcom/example/hanlei/first_demo/MainActivity;
    
        const-class v3, Lcom/example/hanlei/first_demo/Main2Activity;
    
        invoke-direct {v1, v2, v3}, Landroid/content/Intent;-><init>(Landroid/content/Context;Ljava/lang/Class ;) V
    
    
        invoke-virtual {v0, v1}, Lcom/example/hanlei/first_demo/MainActivity;->startActivity(Landroid/content/Intent ;) V

    我们看到了两个if语言
    整个逻辑就是先进行一个判断,然后进行另外一个判断。就是满足第一个if语句,然后满足第二个if语句才到结束。
    这些smali代码就是我们之前分析过很多次的语句,没有什么难的地方,都很简单的。

    0×03 暴力美学

    我们来尝试破解。

    方法 1

    思路

    既然有if语句进行判断,那我把if语句删了。编程现在这个样子:

    invoke-static {v0}, Lcom/example/hanlei/first_demo/MainActivity;->access$000(Lcom/example/hanlei/first_demo/MainActivity ;) Landroid/widget/EditText
    ;
    
        move-result-object v0
    
        invoke-virtual {v0}, Landroid/widget/EditText;->getText()Landroid/text/安卓手机怎么设置双击亮屏教程

    MSM8909的触摸屏驱动导致的熄屏后重新亮屏速度慢的原因!

    python3:判断手机的亮屏状态

    华为平板突然黑屏如何解决?

    请问Mac如何不熄屏?

    fastlane 抓屏和快照