赞
踩
手机自动亮度失效,调节亮度条屏幕闪烁
1.android.hardware.light@2.0-service转换亮度值出问题,导致调节屏幕亮度异常
2.kernel设置的最大亮度值有问题,导致无法调大最大亮度
在分析之前我们得大概知道自动亮度的流程整个流程,设置亮度主要通过slpi, android.hardware.sensors@1.0-service,system_server,android.hardware.light@2.0-service,kernel来五部分来共同完成。
1.slpi部分,这部分主要是光感循环读取数据,然后通过pb_send_sensor_stream_event/pb_send_event将数据发生给子系统,子系统最后会通过qmi接口将数据传给android.hardware.sensors@1.0-service。
2.android.hardware.sensors@1.0-service拿到数据后会继续传递给system_server. 这部分的具体传递过程这里就不说了,可以看一下我以前画的流程图:https://blog.csdn.net/aa787282301/article/details/84665319。
3.System_server是拿到sensor 传递过来的lux数据后会进行一系列的计算,然后得出当前的亮度值,传递给android.hardware.light@2.0-service进程。
4.android.hardware.light@2.0-service进程会把亮度值写到kernel的brightnes设备节点。
5.kernel拿到亮度值后,就去改变屏幕的亮度。
有了2.1的知识基础后我们也分进程来排查问题就好了:
1.slpi的排查可以直接在上传数据的时候打印出对应的lux值,然后看看是否符合预期,例如:
- TCS3701_SPRINTF(LOW, sns_fw_printf, "TCS3701 pb_send_sensor_stream_event: lux: %f\n", report_data[0]);
- pb_send_sensor_stream_event(instance,
- &state->als_info.als_suid,
- sns_get_system_time(),
- SNS_STD_SENSOR_MSGID_SNS_STD_SENSOR_EVENT,
- SNS_STD_SENSOR_SAMPLE_STATUS_ACCURACY_HIGH,
- report_data,
- ALS_EVENT_SIZE,
- state->encoded_als_event_len);
然后我们直接用qxdm来看lux值是不是符合预期的,如果lux值是正确的,那我们就继续看其他进程。本节说的问题并不是tcs3701数据采集有问题,这里就不详细分析了。
2.android.hardware.sensors@1.0-service进程拿到slpi的数据后不会进过特别多的处理,会继续传递给system_server,一般情况下不会有问题。
3.system_server拿到值lux值后会做比较多的处理,过程比较复杂,我们直接看到最后,就是它要设置的亮度值:
- private void setDisplayBrightness(int brightness) {
- if (DEBUG) {
- Slog.d(TAG, "setDisplayBrightness("
- + "id=" + displayId + ", brightness=" + brightness + ")");
- }
-
- Trace.traceBegin(Trace.TRACE_TAG_POWER, "setDisplayBrightness("
- + "id=" + displayId + ", brightness=" + brightness + ")");
- try {
- mBacklight.setBrightness(brightness);
- Trace.traceCounter(Trace.TRACE_TAG_POWER,
- "ScreenBrightness", brightness);
- } finally {
- Trace.traceEnd(Trace.TRACE_TAG_POWER);
- }
- }
这里是通过mBacklight.setBrightness(brightness)来进行设置亮度,我们将DEBUG改为true,然后用手电筒照射手机,看看这里的日志是否正常:
- 01-01 00:06:47.649 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=95)
- 01-01 00:06:47.679 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=81)
- 01-01 00:06:47.699 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=61)
- 01-01 00:06:47.726 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=52)
- 01-01 00:06:47.743 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=43)
- 01-01 00:06:47.770 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=36)
- 01-01 00:06:47.816 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=30)
- 01-01 00:06:47.836 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=28)
- 01-01 00:06:47.863 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=27)
- 01-01 00:06:47.876 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=26)
- 01-01 00:06:47.942 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=27)
- 01-01 00:06:47.963 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=30)
- 01-01 00:06:47.984 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=41)
- 01-01 00:06:48.005 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=64)
- 01-01 00:06:48.027 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=100)
- 01-01 00:06:48.058 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=177)
- 01-01 00:06:48.082 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=203)
- 01-01 00:06:48.099 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=233)
- 01-01 00:06:48.122 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=287)
- 01-01 00:06:48.146 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=347)
- 01-01 00:06:48.161 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=413)
- 01-01 00:06:48.182 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=513)
- 01-01 00:06:48.202 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=632)
- 01-01 00:06:48.223 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=792)
- 01-01 00:06:48.248 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=886)
- 01-01 00:06:48.281 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=1237)
- 01-01 00:06:48.311 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=1611)
- 01-01 00:06:48.348 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=1956)
- 01-01 00:06:48.378 1517 2429 D LocalDisplayAdapter: setDisplayBrightness(id=0, brightness=2047)
从日志中我们能看到,亮度值随着亮度增加而增大,所以system_server的代码走到mBacklight.setBrightness(brightness)时还是正常的,我们继续往后排查。
4.system_server将要设置的亮度值继续传递给android.hardware.light@2.0-service进程,android.hardware.light@2.0-service进程最后会打开对应的设备节点,然后把亮度值写进去,具体代码如下:
- char const*const LCD_FILE
- = "/sys/class/leds/lcd-backlight/brightness";
-
- char const*const LCD_FILE2
- = "/sys/class/backlight/panel0-backlight/brightness";
-
- char const*const BUTTON_FILE
- = "/sys/class/leds/button-backlight/brightness";
-
- char const*const PERSISTENCE_FILE
- = "/sys/class/graphics/fb0/msm_fb_persist_mode";
-
- ......
-
- static int
- set_light_backlight(struct light_device_t* dev,
- struct light_state_t const* state)
- {
- int err = 0;
-
- #ifdef USE_AOSP_BACKLIGHT_SOLUTION
- int brightness = 0;
- if(rgb_to_brightness(state) == 0) {
- brightness = 0;
- } else {
- ALOGE("set_light_backlight state->color is %d\n", state->color);
- brightness = (rgb_to_brightness(state)+1)* backlight_conversion;
- ALOGE("%s: brightness is %d\n", __FUNCTION__, brightness);
- }
- #else
- int brightness = state->color & 0xfff;
- #endif
-
- unsigned int lpEnabled =
- state->brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE;
- if(!dev) {
- return -1;
- }
-
- pthread_mutex_lock(&g_lock);
- // Toggle low persistence mode state
- bool persistence_mode = ((g_last_backlight_mode != state->brightnessMode && lpEnabled) ||
- (!lpEnabled &&
- g_last_backlight_mode == BRIGHTNESS_MODE_LOW_PERSISTENCE));
- bool cannot_handle_persistence = !g_has_persistence_node && persistence_mode;
- if (g_has_persistence_node) {
- if (persistence_mode) {
- if ((err = write_int(PERSISTENCE_FILE, lpEnabled)) != 0) {
- ALOGE("%s: Failed to write to %s: %s\n", __FUNCTION__,
- PERSISTENCE_FILE, strerror(errno));
- }
- if (lpEnabled != 0) {
- brightness = DEFAULT_LOW_PERSISTENCE_MODE_BRIGHTNESS;
- }
- }
- g_last_backlight_mode = state->brightnessMode;
- }
-
- if (!err) {
- if (!access(LCD_FILE, F_OK)) {
- err = write_int(LCD_FILE, brightness);
- } else {
- ALOGE("%s: pzc write to %s: %d\n", __FUNCTION__,
- LCD_FILE2, brightness);
- err = write_int(LCD_FILE2, brightness);
- }
- }
-
- pthread_mutex_unlock(&g_lock);
- return cannot_handle_persistence ? -ENOSYS : err;
- }
上层更新亮度值就是往/sys/class/backlight/panel0-backlight/brightness设备节点写值,调用的write_int方法,我在代码里加了一些日志,编译出so后push进手机:
- pzc@pzc-OptiPlex-7050:~/code/hardware/qcom/display/liblight$ mm
- pzc@pzc-OptiPlex-7050:cd ~/code/out/target/product/xxx/vendor/lib64/hw
- pzc@pzc-OptiPlex-7050:~/code/out/target/product/xxx/vendor/lib64/hw$ adb root
- restarting adbd as root
- pzc@pzc-OptiPlex-7050:~/code/out/target/product/xxx/vendor/lib64/hw$
- pzc@pzc-OptiPlex-7050:~/code/out/target/product/xxx/vendor/lib64/hw$ adb remount
- remount succeeded
- pzc@pzc-OptiPlex-7050:~/code/out/target/product/xxx/vendor/lib64/hw$ adb push lights.sm6150.so /vendor/lib64/hw/
- lights.sm6150.so: 1 file pushed. 2.0 MB/s (68784 bytes in 0.032s)
- pzc@pzc-OptiPlex-7050:~/code/out/target/product/xxx/vendor/lib64/hw$ adb reboot
然后我们查看相应的日志:
- 130|xxx:/ $ ps -ef | grep light
- system 675 1 1 23:59:52 ? 00:00:01 android.hardware.light@2.0-service
- shell 5204 3668 5 00:02:15 pts/0 00:00:00 grep light
- xxx:/ $ logcat | grep 675
- 01-01 00:01:32.647 675 675 E qdlights: set_light_backlight state->color is 1360
- 01-01 00:01:32.647 675 675 E qdlights: set_light_backlight: brightness is 96
- 01-01 00:01:32.647 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 96
- 01-01 00:01:32.664 675 675 E qdlights: set_light_backlight state->color is 1420
- 01-01 00:01:32.664 675 675 E qdlights: set_light_backlight: brightness is 152
- 01-01 00:01:32.664 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 152
- 01-01 00:01:32.681 675 675 E qdlights: set_light_backlight state->color is 1487
- 01-01 00:01:32.681 675 675 E qdlights: set_light_backlight: brightness is 216
- 01-01 00:01:32.681 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 216
- 01-01 00:01:32.698 675 675 E qdlights: set_light_backlight state->color is 1558
- 01-01 00:01:32.698 675 675 E qdlights: set_light_backlight: brightness is 56
- 01-01 00:01:32.698 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 56
- 01-01 00:01:32.714 675 675 E qdlights: set_light_backlight state->color is 1621
- 01-01 00:01:32.714 675 675 E qdlights: set_light_backlight: brightness is 112
- 01-01 00:01:32.714 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 112
- 01-01 00:01:32.730 675 675 E qdlights: set_light_backlight state->color is 1687
- 01-01 00:01:32.730 675 675 E qdlights: set_light_backlight: brightness is 168
- 01-01 00:01:32.730 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 168
- 01-01 00:01:32.747 675 675 E qdlights: set_light_backlight state->color is 1745
- 01-01 00:01:32.747 675 675 E qdlights: set_light_backlight: brightness is 224
- 01-01 00:01:32.747 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 224
- 01-01 00:01:32.763 675 675 E qdlights: set_light_backlight state->color is 1795
- 01-01 00:01:32.763 675 675 E qdlights: set_light_backlight: brightness is 40
- 01-01 00:01:32.764 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 40
- 01-01 00:01:32.780 675 675 E qdlights: set_light_backlight state->color is 1851
- 01-01 00:01:32.780 675 675 E qdlights: set_light_backlight: brightness is 88
- 01-01 00:01:32.780 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 88
- 01-01 00:01:32.797 675 675 E qdlights: set_light_backlight state->color is 1903
- 01-01 00:01:32.798 675 675 E qdlights: set_light_backlight: brightness is 136
- 01-01 00:01:32.798 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 136
- 01-01 00:01:32.813 675 675 E qdlights: set_light_backlight state->color is 1962
- 01-01 00:01:32.813 675 675 E qdlights: set_light_backlight: brightness is 192
- 01-01 00:01:32.813 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 192
- 01-01 00:01:32.831 675 675 E qdlights: set_light_backlight state->color is 2018
- 01-01 00:01:32.831 675 675 E qdlights: set_light_backlight: brightness is 240
- 01-01 00:01:32.831 675 675 E qdlights: set_light_backlight: pzc write to /sys/class/backlight/panel0-backlight/brightness: 240
从这日志我们能发现state->color的值是正确的,计算过后的brightness错误了,在亮度变大的过程中brightness由0增加,到达250多又从0开始。从日志中我们就得到了和测试反馈一样的闪屏现象。
- #ifdef USE_AOSP_BACKLIGHT_SOLUTION
- int brightness = 0;
- if(rgb_to_brightness(state) == 0) {
- brightness = 0;
- } else {
- ALOGE("set_light_backlight state->color is %d\n", state->color);
- brightness = (rgb_to_brightness(state)+1)* backlight_conversion;
- ALOGE("%s: brightness is %d\n", __FUNCTION__, brightness);
- }
- #else
- int brightness = state->color & 0xfff;
- #endif
继续看能发现有个宏定义,在定义了USE_AOSP_BACKLIGHT_SOLUTION的情况下数据会经过计算,反之就&2048(屏幕亮度的最大值)。
因为这是我们自己加的代码就不详细展开了,这个宏定义是为了区分原生版本和MIUI版本的,原生版本的最大亮度值是256,MIUI版本是2048,因为这个宏被定义了导致计算出错,最终导致屏幕闪烁,解决办法只需要在我们的版本中去掉这个宏定义,然后就能解决这个闪烁的问题了。
再解决闪烁问题之后,接着又遇到一个新问题,我们调屏幕亮度的时候调到一半就调不动了。。。。然后继续看相关日志,这次发现亮度值确实已经正确的写进了/sys/class/backlight/panel0-backlight/brightness设备节点了,但是亮度只能调节一段范围,继续打印日志分析:
- int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl)
- {
- ......
- pr_debug("backlight type:%d lvl:%d\n", bl->type, bl_lvl);
-
- if (0 == bl_lvl)
- dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_DISP_DIMMINGOFF);
-
- ......
- panel->last_bl_lvl = bl_lvl;
- return rc;
- }
我们能在kernel设置亮度的流程发现有打印日志的地方,我们把日志打印出来看一下:
- xxx:/ # echo "func dsi_panel_set_backlight +tp" > /d/dynamic_debug/control
- xxx:/ # dmesg | grep dsi_panel_set_backlight
- [ 63.406678] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:208
- [ 63.506478] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:216
- [ 63.524899] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:224
- [ 63.539299] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:240
- [ 63.557805] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:264
- [ 63.573974] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:288
- [ 63.592018] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:313
- [ 63.608887] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:345
- ......
- [ 65.219863] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:2047
- [ 65.237156] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:2047
- [ 65.256433] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:2047
- [ 65.271771] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:2047
- [ 65.289537] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:2047
- [ 65.305404] [689] msm-dsi-panel:[dsi_panel_set_backlight:708] backlight type:2 lvl:2047
我们能发现当我们调节亮度条时,亮度调只调了一半(上层设置的值还没到2047),kernel中对应的亮度值已经到了2047了,所以我们得看看这之前亮度值发生了什么变化,直接找到写brightness节点的入口方法:
- static ssize_t brightness_store(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
- {
- int rc;
- struct backlight_device *bd = to_backlight_device(dev);
- unsigned long brightness;
-
- rc = kstrtoul(buf, 0, &brightness);
- if (rc)
- return rc;
-
- bd->usr_brightness_req = brightness;
-
- pr_err("pzc brightness_store1 buf:%s\n", buf);
- pr_err("pzc brightness_store1 brightness:%lu\n", brightness);
-
- pr_err("pzc brightness_store1 bd->thermal_brightness_limit:%lu\n", bd->thermal_brightness_limit);
- pr_err("pzc brightness_store1 bd->usr_brightness_req:%lu\n", bd->usr_brightness_req);
-
- brightness = (brightness <= bd->thermal_brightness_limit) ?
- bd->usr_brightness_req :
- bd->thermal_brightness_limit;
- pr_err("pzc brightness_store2 brightness:%lu\n", brightness);
-
- rc = backlight_device_set_brightness(bd, brightness);
-
- return rc ? rc : count;
- }
这里我们能看到brightness 会和bd->thermal_brightness_limit做对比,取小的值。看着就很符合我们的日志现象,直接加个日志看看吧:
- [ 2513.153084] backlight: pzc brightness_store1 buf:405\x0a
- [ 2513.153087] backlight: pzc brightness_store1 brightness:405
- [ 2513.153088] backlight: pzc brightness_store1 bd->thermal_brightness_limit:255
- [ 2513.153089] backlight: pzc brightness_store1 bd->usr_brightness_req:405
- [ 2513.153090] backlight: pzc brightness_store2 brightness:255
- [ 2513.153092] backlight: pzc backlight_device_set_brightness 255
日志中我们能看到bd->thermal_brightness_limit就是255,这里限制了设置亮度的最大值为255,那我们接着找看看这个bd->thermal_brightness_limit的值在哪里被设置的:
- static int bd_cdev_set_cur_brightness(struct thermal_cooling_device *cdev,
- unsigned long state)
- {
- struct backlight_device *bd = (struct backlight_device *)cdev->devdata;
- int brightness_lvl;
-
- dump_stack();
- pr_err("pzc1 bd_cdev_set_cur_brightness bd->props.max_brightness:%lu\n", bd->props.max_brightness);
- pr_err("pzc1 bd_cdev_set_cur_brightness state:%lu\n", state);
- brightness_lvl = bd->props.max_brightness - state;
- if (brightness_lvl == bd->thermal_brightness_limit)
- return 0;
-
- pr_err("pzc1 brightness_store1 brightness_lvl:%lu\n", brightness_lvl);
-
- bd->thermal_brightness_limit = brightness_lvl;
- brightness_lvl = (bd->usr_brightness_req
- <= bd->thermal_brightness_limit) ?
- bd->usr_brightness_req :
- bd->thermal_brightness_limit;
- backlight_device_set_brightness(bd, brightness_lvl);
-
- return 0;
- }
这里的bd->thermal_brightness_limit = bd->props.max_brightness - state,打印日志后可以看到bd->props.max_brightness =255,state=0,我们接着看看bd->props.max_brightness在哪里被设置的:
- static int sde_backlight_setup(struct sde_connector *c_conn,
- struct drm_device *dev)
- {
- ......
- bl_config = &display->panel->bl_config;
- props.max_brightness = bl_config->brightness_max_level;
- props.brightness = bl_config->brightness_max_level;
- ......
-
- return 0;
- }
props.max_brightness又等于bl_config->brightness_max_level,继续看看brightness_max_level在哪里被设置的:
- static int dsi_panel_parse_bl_config(struct dsi_panel *panel)
- {
- ......
- rc = utils->read_u32(utils->data, "qcom,mdss-brightness-max-level",
- if (rc) {
- pr_debug("[%s] brigheness-max-level unspecified, defaulting to 255\n",
- panel->name);
- panel->bl_config.brightness_max_level = 255;
- } else {
- panel->bl_config.brightness_max_level = val;
- }
- ......
- error:
- return rc;
- }
到了这里我们最终找到了设置最大亮度的地方,是在dtbo文件中进行了配置:
qcom,mdss-brightness-max-level = <255>;
我们将这里修改为2047:
qcom,mdss-brightness-max-level = <2047>;
打包后再进行测试,自动亮度和亮度调节都恢复正常了。
这里一共出现了两个问题,一个是上层亮度转换出错导致了亮度值设置异常,另一个是kernel默认的最大亮度值设置错误,导致屏幕无法调节到真正的最大亮度值。在分析问题的时候可以把问题分不同的层级逐一排查缩小范围,然后再针对某个点单独进行的深入分析,能够提高不少效率。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。