第十三章:LightsService

2020-04-20  本文已影响0人  momxmo

简介

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

五、HAL逻辑实现

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

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

操作驱动文件目录:

/sys/class/leds/

总结:

调用流程

android 灯光流程分析.jpg
上一篇 下一篇

猜你喜欢

热点阅读