美文网首页
第十三章:LightsService

第十三章:LightsService

作者: momxmo | 来源:发表于2020-04-20 19:07 被阅读0次

    简介

    LightsService灯光服务提供了LCD背光灯、键盘灯、按键灯、警示灯、电池灯、消息通知灯、蓝牙灯、wifi灯等八种类型灯光;

    常用到的地方为:PowerManagerNotificationManagerBatteryService等API会调用灯光服务控制灯光显示以及颜色、时长;
    涉及到代码:

    调用api类:
    frameworks/base/services/core/java/com/android/server/notification/NotificationManagerService.java
    frameworks/base/services/core/java/com/android/server/power/PowerManagerService.java
    
    内部实现类
    frameworks/base/services/core/java/com/android/server/lights/LightsManager.java
    frameworks/base/services/core/java/com/android/server/lights/LightsService.java
    frameworks/base/services/core/java/com/android/server/lights/Light.java
    
    JNI层:
    frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp//调用硬件抽象层ILight.h
    
    C逻辑层:
    //例如:华为nexus 6p实现  读写驱动文件
    hardware/libhardware/include/hardware/lights.h //硬件库
    device/huawei/angler/liblight/lights.c
    
    硬件抽象层:
    hardware/interfaces/light/2.0/ILight.hal  //抽象接口
    
    
    
    内核层:
    驱动层:
    //驱动文件一般位于kernel下面,根据不同的硬件厂商而有所不同。
    //驱动程序会监测上面提到的所有节点文件是否被写入,如果节点文件有写入不同的值,那么驱动程序会读取该值 ,并依据具体情况设定不同的LED灯状态。驱动文件详情不再详述。
    

    注意:linux中的所有操作都是通过文件的形式,所以LED的最终操作也是通过读写节点文件来实现的 该类中提供了操作LED灯节点文件的方法,通过向节点文件写入数据,位于kernel下面的LED灯的驱动程序会检测到文件的改动,进而对LED的状态根据写入的值进行重新设定。

    灯系统架构图

    image.png

    一、启动 --->(Java层分析)

    启动位置
    frameworks/base/services/java/com/android/server/SystemServer.java
    跟其他系统服务一样, LightsService也是继承于SystemService并通过SystemServer启动。

    public final class SystemServer {
    private void startBootstrapServices() {
        .....
        mSystemServiceManager.startService(LightsService.class);
        .....
    }
    }
    

    构造函数
    创建Light 灯光对象,多种类型存放数组中;LightImplLight的具体实现;
    frameworks/base/services/core/java/com/android/server/lights/LightsService.java

    public class LightsService extends SystemService {
        public LightsService(Context context) {
            super(context);
            for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) {
                mLights[i] = new LightImpl(i);
            }
        }
    }
    

    onStart()对外开发服务
    提供获取Light灯光,实现控制

         @Override
          public void onStart() {
            publishLocalService(LightsManager.class, mService);
          }
         private final LightsManager mService = new LightsManager() {
            @Override
            public Light getLight(int id) {
                if (0 <= id && id < LIGHT_ID_COUNT) {
                    return mLights[id];
                } else {
                    return null;
                }
            }
          };
    

    LightsManager灯光管理抽象类
    定义了8中灯光类型;LIGHT_ID_COUNT记录硬件支持的灯光类型数量;
    frameworks/base/services/core/java/com/android/server/lights/LightsManager.java

    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;
        public static final int LIGHT_ID_WIFI = Type.WIFI;
        public static final int LIGHT_ID_COUNT = Type.COUNT;
    
        public abstract Light getLight(int id);
    }
    

    Light灯光对象
    对灯光类型进行封装抽象
    frameworks/base/services/core/java/com/android/server/lights/Light.java

    public abstract class Light {
        public static final int LIGHT_FLASH_NONE = Flash.NONE;
        public static final int LIGHT_FLASH_TIMED = Flash.TIMED;
        public static final int LIGHT_FLASH_HARDWARE = Flash.HARDWARE;
    
        /**
         * Light brightness is managed by a user setting.
         */
        public static final int BRIGHTNESS_MODE_USER = Brightness.USER;
    
        /**
         * Light brightness is managed by a light sensor.
         */
        public static final int BRIGHTNESS_MODE_SENSOR = Brightness.SENSOR;
    
        /**
         * Low-persistence light mode.
         */
        public static final int BRIGHTNESS_MODE_LOW_PERSISTENCE = Brightness.LOW_PERSISTENCE;
    
        public abstract void setBrightness(int brightness);
        public abstract void setBrightness(int brightness, int brightnessMode);
        public abstract void setColor(int color);
        public abstract void setFlashing(int color, int mode, int onMS, int offMS);
        public abstract void pulse();
        public abstract void pulse(int color, int onMS);
        public abstract void turnOff();
        public abstract void setVrMode(boolean enabled);
    }
    

    LightImpl 是对抽象Light 的具体实现
    LightImplLightsService的内部私有类

     private final class LightImpl extends Light {
      @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;
                    }
    
                    int color = brightness & 0x000000ff;
                    color = 0xff000000 | (color << 16) | (color << 8) | color;
                    setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode);
                }
            }
    }
    

    这个方法是设置灯的亮度值,它最终会将这个亮度brightness(取值范围0~255)转换成色彩值color(ARGB)。我们知道颜色都是三基色RGB组成的,我们要控制的灯基本上都是单色的,要么是红色,要么是绿色。所以在转换过程中,是将亮度值对应的数值分别设置到RGB三色中,也就是每一个单色上都设置为跟亮度相同的数值,这样无论控制的是什么颜色的灯,都会将亮度值设置为brightness。其中0xff000000表示的是ARGB模式,A表示的是透明度。在实际操作过程中,只要亮度值大于0,设置任意数值都会起到相同的作用,都能够达到点亮灯的效果。
    setLightLocked()方法
    最终会通过JNI调用底层设置灯光

       private void setLightLocked(int color, int mode, int onMS, int offMS, int brightnessMode) {
              ......
                    mInitialized = true;
                    mLastColor = mColor;
                    mColor = color;
                    mMode = mode;
                    mOnMS = onMS;
                    mOffMS = offMS;
                    mBrightnessMode = brightnessMode;
              .........
                        setLight_native(mId, color, mode, onMS, offMS, brightnessMode);
                ........
                }
    //JNI调用
     static native void setLight_native(int light, int color, int mode,
                int onMS, int offMS, int brightnessMode);
            }
    

    二、JNI调用 --->(JNI层分析)

    java层对灯光的操作最终到会通过JNI调用硬件抽象层;
    frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
    LightsService调用了LightsService.cpp的本地方法,下面看一下该类。

    #define LOG_TAG "LightsService"
    
    #include "jni.h"
    #include "JNIHelp.h"
    #include "android_runtime/AndroidRuntime.h"
    //关键引入ILight模块和types模块接口
    #include <android/hardware/light/2.0/ILight.h>
    #include <android/hardware/light/2.0/types.h>
    #include <utils/misc.h>
    #include <utils/Log.h>
    #include <map>
    #include <stdio.h>
    
    namespace android {
    
    using Brightness = ::android::hardware::light::V2_0::Brightness;
    using Flash      = ::android::hardware::light::V2_0::Flash;
    using ILight     = ::android::hardware::light::V2_0::ILight;
    using LightState = ::android::hardware::light::V2_0::LightState;
    using Status     = ::android::hardware::light::V2_0::Status;
    using Type       = ::android::hardware::light::V2_0::Type;
    template<typename T>
    using Return     = ::android::hardware::Return<T>;
    
    class LightHal {
    private:
        static sp<ILight> sLight;
        static bool sLightInit;
    
        LightHal() {}
    
    public:
        static void disassociate() {
            sLightInit = false;
            sLight = nullptr;
        }
    
        static sp<ILight> associate() {
            if ((sLight == nullptr && !sLightInit) ||
                    (sLight != nullptr && !sLight->ping().isOk())) {
                // will return the hal if it exists the first time.
              //如果硬件接口已实现,将返回硬件接口
    //HAL 服务获取: HIDL 接口,从 servicemanager 中获取 Light 服务
    //具体请看:https://blog.csdn.net/wangjun7121/article/details/88140862
    
                sLight = ILight::getService();
                sLightInit = true;
    
                if (sLight == nullptr) {
                    ALOGE("Unable to get ILight interface.");
                }
            }
    
            return sLight;
        }
    };
    
    sp<ILight> LightHal::sLight = nullptr;
    bool LightHal::sLightInit = false;
    
        //检测java传入的参数是否合法
    static bool validate(jint light, jint flash, jint brightness) {
        bool valid = true;
        //灯类型是否在有效区间内
        if (light < 0 || light >= static_cast<jint>(Type::COUNT)) {
            ALOGE("Invalid light parameter %d.", light);
            valid = false;
        }
    //闪光类型是否正确 枚举类型
        if (flash != static_cast<jint>(Flash::NONE) &&
            flash != static_cast<jint>(Flash::TIMED) &&
            flash != static_cast<jint>(Flash::HARDWARE)) {
            ALOGE("Invalid flash parameter %d.", flash);
            valid = false;
        }
    //亮度是否合法
        if (brightness != static_cast<jint>(Brightness::USER) &&
            brightness != static_cast<jint>(Brightness::SENSOR) &&
            brightness != static_cast<jint>(Brightness::LOW_PERSISTENCE)) {
            ALOGE("Invalid brightness parameter %d.", brightness);
            valid = false;
        }
    
        if (brightness == static_cast<jint>(Brightness::LOW_PERSISTENCE) &&
            light != static_cast<jint>(Type::BACKLIGHT)) {
            ALOGE("Cannot set low-persistence mode for non-backlight device.");
            valid = false;
        }
    
        return valid;
    }
    
    static LightState constructState(
            jint colorARGB,
            jint flashMode,
            jint onMS,
            jint offMS,
            jint brightnessMode){
        Flash flash = static_cast<Flash>(flashMode);
        Brightness brightness = static_cast<Brightness>(brightnessMode);
    
        LightState state{};
    
        if (brightness == Brightness::LOW_PERSISTENCE) {
            state.flashMode = Flash::NONE;
        } else {
            // Only set non-brightness settings when not in low-persistence mode
            state.flashMode = flash;
            state.flashOnMs = onMS;
            state.flashOffMs = offMS;
        }
    
        state.color = colorARGB;
        state.brightnessMode = brightness;
    
        return state;
    }
    
    static void processReturn(
            const Return<Status> &ret,
            Type type,
            const LightState &state) {
        if (!ret.isOk()) {
            ALOGE("Failed to issue set light command.");
            LightHal::disassociate();
            return;
        }
    
        switch (static_cast<Status>(ret)) {
            case Status::SUCCESS:
                break;
            case Status::LIGHT_NOT_SUPPORTED:
                ALOGE("Light requested not available on this device. %d", type);
                break;
            case Status::BRIGHTNESS_NOT_SUPPORTED:
                ALOGE("Brightness parameter not supported on this device: %d",
                    state.brightnessMode);
                break;
            case Status::UNKNOWN:
            default:
                ALOGE("Unknown error setting light.");
        }
    }
    //java层调用JNI方法的实现
    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<>是安卓特有的智能指针(不用专门去维护内存回收);也可以说是强指针
        sp<ILight> hal = LightHal::associate();
        if (hal == nullptr) {
            return;
        }
    
        Type type = static_cast<Type>(light);
        LightState state = constructState(
            colorARGB, flashMode, onMS, offMS, brightnessMode);
    
        {
            ALOGD_IF_SLOW(50, "Excessive delay setting light");
            Return<Status> ret = hal->setLight(type, state);
            processReturn(ret, type, state);
        }
    }
    //注册方法表
    static const JNINativeMethod method_table[] = {
        { "setLight_native", "(IIIIII)V", (void*)setLight_native },
    };
    //入口函数,注册方法
    int register_android_server_LightsService(JNIEnv *env) {
        return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
                method_table, NELEM(method_table));
    }
    
    };
    

    三、HIDL 接口 定义

    HIDL实战笔记

    HIDL服务Light流程介绍

    hardware/interfaces/light/2.0/ILight.hal
    hardware/interfaces/light/2.0/types.hal

    package android.hardware.light@2.0;
    
    interface ILight {
    
        /**
         * Set the provided lights to the provided values.
         *
         * @param type logical light to set
         * @param state describes what the light should look like.
         * @return status result of applying state transformation.
         */
        setLight(Type type, LightState state) generates (Status status);
    
        /**
         * Discover what indicator lights are available.
         *
         * @return types list of available lights
         */
        getSupportedTypes() generates (vec<Type> types);
    
    };
    

    HIDL客户端与服务端通过Binder通讯实现流程图:


    image.png

    其实主要是就是将以前那种 Java-> Jni -> Hal -> Kernel 的结构变成了
    Java -> Jni -> Binder 客户端 ====== Binder 通信 ======> Binder 服务端 -> Hal -> Kernel
    将 framework 与 Hal 之间的交互变成了 CS 结构了。

    四、HIDL 服务端

    hardware/interfaces/light目录如下:

    image.png
    • 1.ILight.halHIDL 接口文件定义
    • 2.types.hal是HIDL定义类型、颜色等;
    • 3.service.cpp是HIDL的HAl提供服务;
    • 4.Light.h头文件,最终引用/hardware/libhardware/include/hardware/lights.h,里面包含灯光类型定义、struct数据结构封装;
    • 4.Light.cppILight.halHIDL 接口的实现,最终会调用

    五、HAL逻辑实现

    负责对驱动文件的读写操作
    (这里采用华为的angler设备 Nexus 6p)
    相关代码:

    /hardware/libhardware/include/hardware/lights.h
    /device/huawei/angler/liblight/lights.c
    

    操作驱动文件目录:

    /sys/class/leds/
    

    总结:

    调用流程

    android 灯光流程分析.jpg

    相关文章

      网友评论

          本文标题:第十三章:LightsService

          本文链接:https://www.haomeiwen.com/subject/akwibhtx.html