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基础逆向
0×00 前言
不知所以然,请看
以及java系列:
内容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.更改布局
然后一个登录密码的框框。
然后还是一个登录按钮
预览一下我们的界面
好丑,做一个简单的调整,整体代码如下:
<?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>
2.绑定控件
恩,为了像一个登录界面,我把name也改了。
所以重新绑定。
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="请输入密码" />
这里加了一行只允许输入数字。
测试
0×02 反编译分析
分析嘛,很多次了。老规矩
1. Android Killer
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/安卓手机怎么设置双击亮屏教程