android 9.0背光调节流程

1.背光服务框架
如下图是背光框架层图
在这里插入图片描述

2.UML时序图
这里主要标出的是各个服务或者框架层之间连接的api,中间会省略一些调用流程。
如下图,PowerManagerService会监听SettingProvider的亮度背光值screen_brightness变化,然后进行背光调节。
该图主要是一些服务之前的通信。
在这里插入图片描述

Jni层访问过程如下图:
jni通过hidl直通式访问light库,对hardware层light库会访问对应的sys节点从而进行背光驱动的访问,最终达到调节
背光的目的。
在这里插入图片描述

注意点:
(1)背光的调节并不是一步到位的,而是通过一个线程按照一定的速度来减少或者增加一个背光亮度值来调节的,例如一般背光的调控范围是0-255,假如目前背光150,用户想要调节到180的话,那么系统会开启一个线程按照一定的速度来每次增加背光亮度值1,连续增加30次来达到调节目的。这样调节的目的可能是为了让用户感受到舒适吧。
核心代码部分如下:

代码路径:base\services\core\java\com\android\server\display\RampAnimator.java

//创建了一个线程
 private final Runnable mAnimationCallback = new Runnable() {
        @Override // Choreographer callback
        public void run() {
            final long frameTimeNanos = mChoreographer.getFrameTimeNanos();
            final float timeDelta = (frameTimeNanos - mLastFrameTimeNanos)
                    * 0.000000001f;
            mLastFrameTimeNanos = frameTimeNanos;

            // Advance the animated value towards the target at the specified rate
            // and clamp to the target. This gives us the new current value but
            // we keep the animated value around to allow for fractional increments
            // towards the target.
            final float scale = ValueAnimator.getDurationScale();
            if (scale == 0) {
                // Animation off.
                mAnimatedValue = mTargetValue;
            } else {
                final float amount = timeDelta * mRate / scale;
                if (mTargetValue > mCurrentValue) {
                    mAnimatedValue = Math.min(mAnimatedValue + amount, mTargetValue);
                } else {
                    mAnimatedValue = Math.max(mAnimatedValue - amount, mTargetValue);
                }
            }
            final int oldCurrentValue = mCurrentValue;
            mCurrentValue = Math.round(mAnimatedValue);

            if (oldCurrentValue != mCurrentValue) {
                //在线程run中调节背光,mProperty是DisplayPowerState对像,
                //base\services\core\java\com\android\server\display\DisplayPowerState.java
                mProperty.setValue(mObject, mCurrentValue);
            }

            if (mTargetValue != mCurrentValue) {
                postAnimationCallback();
            } else {
                mAnimating = false;
                if (mListener != null) {
                    mListener.onAnimationEnd();
                }
            }
        }
    };

(2)如何获取从灯光服务中确定背光调用对象
LightsService是一个有关光调节的服务,其中包括了背光,按键灯,无线通信指示灯等的控制,DisplayService与LightsService通信主要是背光调节,那么DisplayService是如何通知或者获取lightservice中背光的调节对象呢?其实如下代码在LocalDisplayDevice对象构建的时候用LightsManager.LIGHT_ID_BACKLIGHT参数明确了获取的LightsService服务中的lights对象为背光调节类型。所以mBacklight.setBrightness(brightness);调用的是背光的灯光对象。

public abstract class LightsManager {
    //背光
    public static final int LIGHT_ID_BACKLIGHT = Type.BACKLIGHT;
    //键盘灯
    public static final int LIGHT_ID_KEYBOARD = Type.KEYBOARD;
    //按键灯
    public static final int LIGHT_ID_BUTTONS = Type.BUTTONS;
    //电池相关灯,可能是充电吧
    public static final int LIGHT_ID_BATTERY = Type.BATTERY;
    //通知类型的灯光
    public static final int LIGHT_ID_NOTIFICATIONS = Type.NOTIFICATIONS;
    public static final int LIGHT_ID_ATTENTION = Type.ATTENTION;
    //蓝牙模块的灯光
    public static final int LIGHT_ID_BLUETOOTH = Type.BLUETOOTH;
    //wifi模块的灯光
    public static final int LIGHT_ID_WIFI = Type.WIFI;
    public static final int LIGHT_ID_COUNT = Type.COUNT;

    public abstract Light getLight(int id);
}


 - [ ] public LocalDisplayDevice(IBinder displayToken, int
       builtInDisplayId,
                       SurfaceControl.PhysicalDisplayInfo[] physicalDisplayInfos, int activeDisplayInfo,
                       int[] colorModes, int activeColorMode) {
                   super(LocalDisplayAdapter.this, displayToken, UNIQUE_ID_PREFIX + builtInDisplayId);
                   mBuiltInDisplayId = builtInDisplayId;
                   updatePhysicalDisplayInfoLocked(physicalDisplayInfos, activeDisplayInfo,
                           colorModes, activeColorMode);
                   updateColorModesLocked(colorModes, activeColorMode);
                   mSidekickInternal = LocalServices.getService(SidekickInternal.class);
                   if (mBuiltInDisplayId == SurfaceControl.BUILT_IN_DISPLAY_ID_MAIN) {
                       //获取光控服务的时候明确表明类型为
                       //LightsManager.LIGHT_ID_BACKLIGHT背光服务类型。
                       LightsManager lights = LocalServices.getService(LightsManager.class);
                       mBacklight = lights.getLight(LightsManager.LIGHT_ID_BACKLIGHT);
                   } else {
                       mBacklight = null;
                   }
                   mHdrCapabilities = SurfaceControl.getHdrCapabilities(displayToken);
               }

LightsService服务getLight实现
上面说displayservice在getLight的时候获取灯光调节对象。下面看看LightsService的getLight方法的实现。

private final LightsManager mService = new LightsManager() {
        @Override
        public Light getLight(int id) {
            if (0 <= id && id < LIGHT_ID_COUNT) {
                return mLights[id];//返回mLights数组的对象
            } else {
                return null;
            }
        }
    };

//mLights是储存LightImpl对象类型的数组
final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT];

public LightsService(Context context) {
        super(context);

        //mLights在LightsService进行初始化赋值
        for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
            mLights[i] = new LightImpl(i);
        }
    }

//LightImpl对象,用一个mId变量来区分以及记录各种灯光调节对象。
private final class LightImpl extends Light {

        private LightImpl(int id) {
            mId = id;
        }
        ......
        ......
}

从上面看出,lightsService只是简单用一个LightImpl类中id值来区分各种灯光调节对象,并且用一个mLights来储存各种灯光对象,对应数组编号就对应各种灯光对象的位置。

(4)hal层利用id值来调用对应灯光调节方法
上面得知lightsservice只是仅仅用id来区分各类灯光调节对象,该id最终如何让灯光准确调用对应的api调节呢?我们先看lightsservice的调用过程,主要分为
(1) LightsService调用流程
(2) jni 层调用
(3) hal层light interface调用:setLight
(4)厂商vendor lights库,以rk为例

//(1):LightsService调用流程:
//代码路径:base\services\core\java\com\android\server\lights\LightsService.java
//留意:传递mId确定灯光调节类型
mBacklight.setBrightness--->setLightLocked--->setLight_native(mId, color, mode, onMS, offMS, brightnessMode);--->jni调用

//(2):jni 层调用:
//jni代码路径:base\services\core\jni\com_android_server_lights_LightsService.cpp
//setLight_native的实现mId实参会把值传递给参数light
static void setLight_native(
        JNIEnv* /* env */,
        jobject /* clazz */,
        jint light,
        jint colorARGB,
        jint flashMode,
        jint onMS,
        jint offMS,
        jint brightnessMode) {

    if (!validate(light, flashMode, brightnessMode)) {
        return;
    }

    sp<ILight> hal = LightHal::associate();

    if (hal == nullptr) {
        return;
    }

    //确定灯光调节类型,这里的type根据上面的参数传递下来是背光
    Type type = static_cast<Type>(light);
    LightState state = constructState(
        colorARGB, flashMode, onMS, offMS, brightnessMode);

    {
        android::base::Timer t;
        //hidl直通式访问,调用hal接口setLight,并传递确定灯光调节类型参数type,
        Return<Status> ret = hal->setLight(type, state);
        processReturn(ret, type, state);
        if (t.duration() > 50ms) ALOGD("Excessive delay setting light");
    }
}

//(3):hal层调用:setLight
//代码路径:./hardware/interfaces/light/2.0/default/Light.cpp
Return<Status> Light::setLight(Type type, const LightState& state)  {
   //根据type类型寻找灯光hal设备,其中可能会为按键灯设备,背光设备,这里是背光
   //mLights储存着各种hal层灯光调剂的设备对象
    auto it = mLights.find(type);

    if (it == mLights.end()) {
        return Status::LIGHT_NOT_SUPPORTED;
    }

    //hwLight 来自mLights中储存的light_device_t* light,表示对应的type,对应相应的灯光设备调节对象
    light_device_t* hwLight = it->second;

    light_state_t legacyState {
        .color = state.color,
        .flashMode = static_cast<int>(state.flashMode),
        .flashOnMS = state.flashOnMs,
        .flashOffMS = state.flashOffMs,
        .brightnessMode = static_cast<int>(state.brightnessMode),
    };

    //调用对应设备的灯光调节api,这里根据上面type参数,hwLight是背光调节设备对象。
    //调用的set_light调用的是set_light_backlight接口,至于为何,请继续看下面
    int ret = hwLight->set_light(hwLight, &legacyState);

    switch (ret) {
        case -ENOSYS:
            return Status::BRIGHTNESS_NOT_SUPPORTED;
        case 0:
            return Status::SUCCESS;
        default:
            return Status::UNKNOWN;
    }
}

//mLights的初始化
//在构造函数Light中初始化,
Light::Light(std::map<Type, light_device_t*> &&lights)
  : mLights(std::move(lights)) {}

//当上层通过hidl直通式打开hal层时,便会调用HIDL_FETCH_ILight,返回值以形参的形式传递给构造函数Light
//mLights指向了即HIDL_FETCH_ILight的返回的值,从而进行了初始化
//看看HIDL_FETCH_ILight的实现,其实就是对间接mLights进行了初始化。
ILight* HIDL_FETCH_ILight(const char* /* name */) {
    std::map<Type, light_device_t*> lights;

    //初始化类型,从kLogicalLights中获取支持的灯光调节类型
    for(auto const &pair : kLogicalLights) {
        Type type = pair.first;
        const char* name = pair.second;
        //根据类型名字,得到灯光调节的设备对象
        light_device_t* light = getLightDevice(name);

        if (light != nullptr) {
            lights[type] = light;
        }
    }

    if (lights.size() == 0) {
        // Log information, but still return new Light.
        // Some devices may not have any lights.
        ALOGI("Could not open any lights.");
    }

    //这里猜想,return的时候便是,对
    return new Light(std::move(lights));
}

//kLogicalLights的定义,确定hal层灯光支持的设备调节类型
const static std::map<Type, const char*> kLogicalLights = {
    {Type::BACKLIGHT,     LIGHT_ID_BACKLIGHT},
    {Type::KEYBOARD,      LIGHT_ID_KEYBOARD},
    {Type::BUTTONS,       LIGHT_ID_BUTTONS},
    {Type::BATTERY,       LIGHT_ID_BATTERY},
    {Type::NOTIFICATIONS, LIGHT_ID_NOTIFICATIONS},
    {Type::ATTENTION,     LIGHT_ID_ATTENTION},
    {Type::BLUETOOTH,     LIGHT_ID_BLUETOOTH},
    {Type::WIFI,          LIGHT_ID_WIFI}
};

//getLightDevice的实现:主要是调用 hwModule->methods->open来打开对应的设备模块,并返回对应灯光调节设备对象。
light_device_t* getLightDevice(const char* name) {
    light_device_t* lightDevice;
    const hw_module_t* hwModule = NULL;

    int ret = hw_get_module (LIGHTS_HARDWARE_MODULE_ID, &hwModule);
    if (ret == 0) {
        //根据name打开对应的灯光调节设备模块
        ret = hwModule->methods->open(hwModule, name,
            reinterpret_cast<hw_device_t**>(&lightDevice));
        if (ret != 0) {
            ALOGE("light_open %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret);
        }
    } else {
        ALOGE("hw_get_module %s %s failed: %d", LIGHTS_HARDWARE_MODULE_ID, name, ret);
    }

    if (ret == 0) {
        return lightDevice;
    } else {
        ALOGE("Light passthrough failed to load legacy HAL.");
        return nullptr;
    }
}



//(4)厂商vendor lights库,以rk为例
//代码路径:./hardware/rockchip/liblights/lights.c
//在上面调用 hwModule->methods->open打开模块时,
//各个平台的vendor,对hal层库中各种灯光设备进行了初始化,例如下面主要接口是set_light
static int open_lights(const struct hw_module_t* module, char const* name,
        struct hw_device_t** device)
{
    int (*set_light)(struct light_device_t* dev,
            struct light_state_t const* state);

    if (0 == strcmp(LIGHT_ID_BACKLIGHT, name)) {
        //背光设备,则上面获取到的是灯光设备的时候,调用set_light调用的是set_light_backlight。
        set_light = set_light_backlight;
        if ((access(LCD_FILE, F_OK) < 0) && (access(LCD_FILE_31, F_OK) < 0))
            return -ENOSYS;
    }
    else if (0 == strcmp(LIGHT_ID_BATTERY, name)) {
        set_light = set_light_battery;
        if (access_rgb() < 0 && access_rgb_blink() < 0)
            return -ENOSYS;
    }
    else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
        set_light = set_light_notifications;
        if (access_rgb() < 0 && access_rgb_blink() < 0)
            return -ENOSYS;
    }
    else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) {
        set_light = set_light_buttons;
        if (access(BUTTON_FILE, F_OK) < 0)
            return -ENOSYS;
    }
    else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) {
        set_light = set_light_attention;
        if (access_rgb() < 0 && access_rgb_blink() < 0)
            return -ENOSYS;
    }
    else
        return -ENOSYS;

    pthread_once(&g_init, init_globals);

    struct light_device_t *dev = malloc(sizeof(struct light_device_t));

    if(!dev)
        return -ENOMEM;

    memset(dev, 0, sizeof(*dev));

    dev->common.tag = HARDWARE_DEVICE_TAG;
    dev->common.version = 0;
    dev->common.module = (struct hw_module_t*)module;
    dev->common.close = (int (*)(struct hw_device_t*))close_lights;
    dev->set_light = set_light;

    *device = (struct hw_device_t*)dev;
    return 0;
}

//set_light_backlight的实现       
static int set_light_backlight(struct light_device_t* dev,
        struct light_state_t const* state)
{
    int err = 0;
    int brightness = rgb_to_brightness(state);
    if(!dev) {
        return -1;
    }
    pthread_mutex_lock(&g_lock);
   //写节点LCD_FILE
   //LCD_FILE的如下定义为: /sys/class/backlight/backlight/brightness,
   //所以主要是通过写节点/sys/class/backlight/backlight/brightness调节背光
    err = write_int(LCD_FILE, brightness);
        /* support for kernel3.10 */
        if (err !=0)
        err = write_int(LCD_FILE_31, brightness);
    pthread_mutex_unlock(&g_lock);
    return err;
}

//LCD_FILE的定义
char const*const LCD_FILE
        = "/sys/class/backlight/backlight/brightness";

``

  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值