09.mtk背光流程

基于 Light 介绍安卓 8.0 HAL 变化

 /frameworks/base/services/core/java/com/android/server/lights/LightsService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149

 public class LightsService extends SystemService {
    static final String TAG = "LightsService";
@Nullable
    private final Supplier<ILights> mVintfLights;
    ... ...
    private final class LightsManagerBinderService extends ILightsManager.Stub {
        ... ...
    }
    ... ...
    public LightsService(Context context) {
        this(context, new VintfHalCache(), Looper.myLooper());
    }

    @VisibleForTesting
    LightsService(Context context, Supplier<ILights> service, Looper looper) {
        super(context);
        mH = new Handler(looper);
        mVintfLights = service.get() != null ? service : null;

        populateAvailableLights(context);
        mManagerService = new LightsManagerBinderService();
    }

    private void populateAvailableLights(Context context) {
        if (mVintfLights != null) {
            populateAvailableLightsFromAidl(context);
        } else {
            populateAvailableLightsFromHidl(context);
        }

        for (int i = mLightsById.size() - 1; i >= 0; i--) {
            final int type = mLightsById.keyAt(i);
            if (0 <= type && type < mLightsByType.length) {
                mLightsByType[type] = mLightsById.valueAt(i);
            }
        }
    }

    private void populateAvailableLightsFromAidl(Context context) {
        try {
            for (HwLight hwLight : mVintfLights.get().getLights()) {
                mLightsById.put(hwLight.id, new LightImpl(context, hwLight));
            }
        } catch (RemoteException ex) {
            Slog.e(TAG, "Unable to get lights from HAL", ex);
        }
    }
    ... ...
    private final class LightImpl extends LogicalLight {
        .... ....
        @Override
        public void setBrightness(float brightness) {
            setBrightness(brightness, BRIGHTNESS_MODE_USER);
        }

        @Override
        public void setBrightness(float brightness, int brightnessMode) {
            if (Float.isNaN(brightness)) {
                Slog.w(TAG, "Brightness is not valid: " + brightness);
                return;
            }
            synchronized (this) {
                // LOW_PERSISTENCE cannot be manually set
                if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
                    Slog.w(TAG, "setBrightness with LOW_PERSISTENCE unexpected #" + mHwLight.id
                            + ": brightness=" + 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) {
                    // New system
                    // 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.
                    if (DEBUG) {
                        Slog.d(TAG, "Using new setBrightness path!");
                    }
                    SurfaceControl.setDisplayBrightness(mDisplayToken, brightness);
                } else {
                    // Old system
                    int brightnessInt = BrightnessSynchronizer.brightnessFloatToInt(
                            getContext(), brightness);
                    int color = brightnessInt & 0x000000ff;
                    color = 0xff000000 | (color << 16) | (color << 8) | color;
                    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 #" + mHwLight.id + ": color=#"
                            + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode);
                }
                mInitialized = true;
                mLastColor = mColor;
                mColor = color;
                mMode = mode;
                mOnMS = onMS;
                mOffMS = offMS;
                mBrightnessMode = brightnessMode;
                setLightUnchecked(color, mode, onMS, offMS, brightnessMode);
            }
        }

        private void setLightUnchecked(int color, int mode, int onMS, int offMS,
                int brightnessMode) {
            Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLightState(" + mHwLight.id + ", 0x"
                    + Integer.toHexString(color) + ")");
            //add for bug1296210
            if (!mSprdLightsUtils.isBatteryOpenWhenNotificationCome(mHwLight.id, color)) {
                try {
                    if (mVintfLights != null) {
                        HwLightState lightState = new HwLightState();
                        lightState.color = color;
                        lightState.flashMode = (byte) mode;
                        lightState.flashOnMs = onMS;
                        lightState.flashOffMs = offMS;
                        lightState.brightnessMode = (byte) brightnessMode;
                        mVintfLights.get().setLightState(mHwLight.id, lightState);  //aidl
                    } else {
                        setLight_native(mHwLight.id, color, mode, onMS, offMS, brightnessMode); //jni->hidl->hal
                    }
                } catch (RemoteException | UnsupportedOperationException ex) {
                    Slog.e(TAG, "Failed issuing setLightState", ex);
                } finally {
                    Trace.traceEnd(Trace.TRACE_TAG_POWER);
                }
            }
        }
        ... ...
    }
    ... ...
    static native void setLight_native(int light, int color, int mode,
            int onMS, int offMS, int brightnessMode);
}

一、通过jni的方式:

1. 8.0之前jni->hal

\frameworks\base\services\core\Android.mk

LOCAL_MODULE := services.core

\frameworks\base\services\core\jni\Android.mk

LOCAL_SRC_FILES += \

    $(LOCAL_REL_DIR)/com_android_server_lights_LightsService.cpp \

 ... ...

 /frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157

/*
 * Copyright (C) 2009 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#define LOG_TAG "LightsService"

#include "jni.h"
#include "JNIHelp.h"
#include "android_runtime/AndroidRuntime.h"

#include <utils/misc.h>
#include <utils/Log.h>
#include <hardware/hardware.h>
#include <hardware/lights.h>  //hal层也include了这个

#include <stdio.h>

namespace android
{

// These values must correspond with the LIGHT_ID constants in
// LightsService.java
enum {
    LIGHT_INDEX_BACKLIGHT = 0,
    LIGHT_INDEX_KEYBOARD = 1,
    LIGHT_INDEX_BUTTONS = 2,
    LIGHT_INDEX_BATTERY = 3,
    LIGHT_INDEX_NOTIFICATIONS = 4,
    LIGHT_INDEX_ATTENTION = 5,
    LIGHT_INDEX_BLUETOOTH = 6,
    LIGHT_INDEX_WIFI = 7,
    LIGHT_COUNT
};

struct Devices {
    light_device_t* lights[LIGHT_COUNT];
};

static light_device_t* get_device(hw_module_t* module, char const* name)
{
    int err;
    hw_device_t* device;
    err = module->methods->open(module, name, &device);  //将二级指针&device传给hal层
    if (err == 0) {                         //hardware/libhardware/include/hardware/lights.h
        return (light_device_t*)device; //强转为与hal层同一类型
    } else {
        return NULL;
    }
}

static jlong init_native(JNIEnv* /* env */, jobject /* clazz */)
{
    int err;
    hw_module_t* module;
    Devices* devices;
    
    devices = (Devices*)malloc(sizeof(Devices));

    err = hw_get_module(LIGHTS_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
    if (err == 0) {
        devices->lights[LIGHT_INDEX_BACKLIGHT]
                = get_device(module, LIGHT_ID_BACKLIGHT);  //保存着hal层赋值的具体函数指针
        devices->lights[LIGHT_INDEX_KEYBOARD]
                = get_device(module, LIGHT_ID_KEYBOARD);
        devices->lights[LIGHT_INDEX_BUTTONS]
                = get_device(module, LIGHT_ID_BUTTONS);
        devices->lights[LIGHT_INDEX_BATTERY]
                = get_device(module, LIGHT_ID_BATTERY);
        devices->lights[LIGHT_INDEX_NOTIFICATIONS]
                = get_device(module, LIGHT_ID_NOTIFICATIONS);
        devices->lights[LIGHT_INDEX_ATTENTION]
                = get_device(module, LIGHT_ID_ATTENTION);
        devices->lights[LIGHT_INDEX_BLUETOOTH]
                = get_device(module, LIGHT_ID_BLUETOOTH);
        devices->lights[LIGHT_INDEX_WIFI]
                = get_device(module, LIGHT_ID_WIFI);
    } else {
        memset(devices, 0, sizeof(Devices));
    }

    return (jlong)devices;
}

static void finalize_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr)
{
    Devices* devices = (Devices*)ptr;
    if (devices == NULL) {
        return;
    }

    free(devices);
}

static void setLight_native(JNIEnv* /* env */, jobject /* clazz */, jlong ptr,
        jint light, jint colorARGB, jint flashMode, jint onMS, jint offMS, jint brightnessMode)
{
    Devices* devices = (Devices*)ptr;
    light_state_t state;

    if (light < 0 || light >= LIGHT_COUNT || devices->lights[light] == NULL) {
        return ;
    }

    uint32_t version = devices->lights[light]->common.version;

    memset(&state, 0, sizeof(light_state_t));

    if (brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE) {
        if (light != LIGHT_INDEX_BACKLIGHT) {
            ALOGE("Cannot set low-persistence mode for non-backlight device.");
            return;
        }
        if (version < LIGHTS_DEVICE_API_VERSION_2_0) {
            // HAL impl has not been upgraded to support this.
            return;
        }
    } else {
        // Only set non-brightness settings when not in low-persistence mode
        state.color = colorARGB;
        state.flashMode = flashMode;
        state.flashOnMS = onMS;
        state.flashOffMS = offMS;
    }

    state.brightnessMode = brightnessMode;

    {
        ALOGD_IF_SLOW(50, "Excessive delay setting light");
        devices->lights[light]->set_light(devices->lights[light], &state); //调用hal层函数指针设置背光
    }
}

static const JNINativeMethod method_table[] = {
    { "init_native", "()J", (void*)init_native },
    { "finalize_native", "(J)V", (void*)finalize_native },
    { "setLight_native", "(JIIIIII)V", (void*)setLight_native },
};

int register_android_server_LightsService(JNIEnv *env)
{
    return jniRegisterNativeMethods(env, "com/android/server/lights/LightsService",
            method_table, NELEM(method_table));
}

};

2. 8.0之后jni->HIDL->HAL

JNI:

\frameworks\base\services\core\jni\Android.mk

cc_library_static {

    name: "libservices.core",

... ...

    srcs: [

       ":lib_alarmManagerService_native",

  "com_android_server_lights_LightsService.cpp",

  ... ...

  ":lib_networkStatsFactory_native",

}

 /frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

#define LOG_TAG "LightsService"
#include <android/hardware/light/2.0/ILight.h> //对应着ILight.hal
#include <android/hardware/light/2.0/types.h>  //对应着types.hal
... ...
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>;

static bool sLightSupported = true;
... ...
static void setLight_native(
        JNIEnv* /* env */,
        jobject /* clazz */,
        jint light,
        jint colorARGB,
        jint flashMode,
        jint onMS,
        jint offMS,
        jint brightnessMode) {

    if (!sLightSupported) {
        return;
    }

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

    Type type = static_cast<Type>(light);
    LightState state = constructState(
        colorARGB, flashMode, onMS, offMS, brightnessMode);

    {
        android::base::Timer t;
        sp<ILight> hal = ILight::getService();  //获取hidl服务
        if (hal == nullptr) {
            sLightSupported = false;
            return;
        }
        Return<Status> ret = hal->setLight(type, state);
        processReturn(ret, type, state);
        if (t.duration() > 50ms) ALOGD("Excessive delay setting light");
    }
}

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 interface:

 /hardware/interfaces/light/2.0/Android.bp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

// This file is autogenerated by hidl-gen -Landroidbp.

hidl_interface {
    name: "[email protected]",
    root: "android.hardware",
    vndk: {
        enabled: true,
    },
    srcs: [
        "types.hal",
        "ILight.hal",
    ],
    interfaces: [
        "[email protected]",
    ],
    gen_java: true,
}

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57

package [email protected];
... ...
/**
 * These light IDs correspond to logical lights, not physical.
 * So for example, if your INDICATOR light is in line with your
 * BUTTONS, it might make sense to also light the INDICATOR
 * light to a reasonable color when the BUTTONS are lit.
 */
enum Type : int32_t {
    BACKLIGHT,
    KEYBOARD,
    BUTTONS,
    BATTERY,
    NOTIFICATIONS,
    ATTENTION,
    BLUETOOTH,
    WIFI,

    COUNT,
};

/**
 * The parameters that can be set for a given light.
 *
 * Not all lights must support all parameters. If you
 * can do something backward-compatible, do it.
 */
struct LightState {
    /**
     * The color of the LED in ARGB.
     *
     * Do your best here.
     *   - If your light can only do red or green, if they ask for blue,
     *     you should do green.
     *   - If you can only do a brightness ramp, then use this formula:
     *      unsigned char brightness = ((77*((color>>16)&0x00ff))
     *              + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;
     *   - If you can only do on or off, 0 is off, anything else is on.
     *
     * The high byte should be ignored. Callers will set it to 0xff (which
     * would correspond to 255 alpha).
     */
    uint32_t color;

    /**
     * To flash the light at a given rate, set flashMode to LIGHT_FLASH_TIMED,
     * and then flashOnMS should be set to the number of milliseconds to turn
     * the light on, followed by the number of milliseconds to turn the light
     * off.
     */
    Flash flashMode;

    int32_t flashOnMs;
    int32_t flashOffMs;

    Brightness brightnessMode;
};

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

package [email protected];

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:

/vendor/mediatek/proprietary/hardware/liblights/2.0/default/[email protected]

service light-hal-2-0 /vendor/bin/hw/[email protected]

    interface [email protected]::ILight default

    class hal

    user system

    group system

    # shutting off lights while powering-off

    shutdown critical

 /vendor/mediatek/proprietary/hardware/liblights/2.0/default/service.cpp

1
2
3
4
5
6
7
8
9
10
11
12

#define NDEBUG 1
#define LOG_TAG "[email protected]"

#include <android/hardware/light/2.0/ILight.h>
#include <hidl/LegacySupport.h>

using android::hardware::light::V2_0::ILight;
using android::hardware::defaultPassthroughServiceImplementation;

int main() {
    return defaultPassthroughServiceImplementation<ILight>();
}

/vendor/mediatek/proprietary/hardware/liblights/2.0/default/Android.mk

LOCAL_PATH := $(call my-dir)    //用于返回当前mk文件路径,由build system提供

include $(CLEAR_VARS)

LOCAL_MODULE_RELATIVE_PATH := hw

LOCAL_MODULE := [email protected]

LOCAL_INIT_RC := [email protected]

LOCAL_SRC_FILES := service.cpp     //生成在\out\target\product\tb8321p3_bsp\vendor\bin\hw\[email protected]

... ...

include $(BUILD_EXECUTABLE)       //对应Android.bp的 cc_binary{

include $(CLEAR_VARS)  //让GNU MAKEFILE为你清除除LOCAL_PATH以外的所有LOCAL_XXX变量,因为所有的编译控制文件都在同一个GNU MAKE执行环境中,所有的变量都是全局的。

LOCAL_MODULE := [email protected]

LOCAL_MODULE_RELATIVE_PATH := hw   //生成在\out\target\product\tb8321p3_bsp\vendor\lib\hw\[email protected]

LOCAL_SRC_FILES := \

    Light.cpp \

... ...

include $(BUILD_SHARED_LIBRARY)     //对应Android.bp的 cc_library_shared{  

 /vendor/mediatek/proprietary/hardware/liblights/2.0/default/Light.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

#ifndef ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H
#define ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H

#include <android/hardware/light/2.0/ILight.h>  //对应着ILight.hal
#include <hardware/hardware.h>
#include <hardware/lights.h>
#include <hidl/Status.h>
#include <hidl/MQDescriptor.h>
#include <map>

#include <cutils/log.h>

namespace android {
namespace hardware {
namespace light {
namespace V2_0 {
namespace implementation {

using ::android::hardware::light::V2_0::ILight;
using ::android::hardware::light::V2_0::LightState;
using ::android::hardware::light::V2_0::Status;
using ::android::hardware::light::V2_0::Type;
using ::android::hardware::Return;
using ::android::hardware::Void;
using ::android::hardware::hidl_vec;
using ::android::hardware::hidl_string;
using ::android::sp;

struct Light : public ILight {
    Light(std::map<Type, light_device_t*> &&lights);

    // Methods from ::android::hardware::light::V2_0::ILight follow.
    Return<Status> setLight(Type type, const LightState& state)  override;
    Return<void> getSupportedTypes(getSupportedTypes_cb _hidl_cb)  override;

private:
    std::map<Type, light_device_t*> mLights;
};

extern "C" ILight* HIDL_FETCH_ILight(const char* name);

}  // namespace implementation
}  // namespace V2_0
}  // namespace light
}  // namespace hardware
}  // namespace android

#endif  // ANDROID_HARDWARE_LIGHT_V2_0_LIGHT_H

 /vendor/mediatek/proprietary/hardware/liblights/2.0/default/Light.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155

/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "Light.h"

namespace android {
namespace hardware {
namespace light {
namespace V2_0 {
namespace implementation {

static_assert(LIGHT_FLASH_NONE == static_cast<int>(Flash::NONE),
    "Flash::NONE must match legacy value.");
static_assert(LIGHT_FLASH_TIMED == static_cast<int>(Flash::TIMED),
    "Flash::TIMED must match legacy value.");
static_assert(LIGHT_FLASH_HARDWARE == static_cast<int>(Flash::HARDWARE),
    "Flash::HARDWARE must match legacy value.");

static_assert(BRIGHTNESS_MODE_USER == static_cast<int>(Brightness::USER),
    "Brightness::USER must match legacy value.");
static_assert(BRIGHTNESS_MODE_SENSOR == static_cast<int>(Brightness::SENSOR),
    "Brightness::SENSOR must match legacy value.");
static_assert(BRIGHTNESS_MODE_LOW_PERSISTENCE ==
    static_cast<int>(Brightness::LOW_PERSISTENCE),
    "Brightness::LOW_PERSISTENCE must match legacy value.");

Light::Light(std::map<Type, light_device_t*> &&lights)
  : mLights(std::move(lights)) {}  //将lights转换为右值,相当于mlights=lights

// Methods from ::android::hardware::light::V2_0::ILight follow.
Return<Status> Light::setLight(Type type, const LightState& state)  {
    auto it = mLights.find(type);  //找到具体light type的light_device_t *(即hal层的函数指针)

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

    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),
    };

    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;
    }
}

Return<void> Light::getSupportedTypes(getSupportedTypes_cb _hidl_cb)  {
    Type *types = new Type[mLights.size()];

    int idx = 0;
    for(auto const &pair : mLights) {
        Type type = pair.first;

        types[idx++] = type;
    }

    {
        hidl_vec<Type> hidl_types{};
        hidl_types.setToExternal(types, mLights.size());

        _hidl_cb(hidl_types);
    }

    delete[] types;

    return Void();
}

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}
};

light_device_t* getLightDevice(const char* name) {
    light_device_tlightDevice;
    const hw_module_t* hwModule = NULL;

    int ret = hw_get_module (LIGHTS_HARDWARE_MODULE_ID, &hwModule);
    if (ret == 0) {
        ret = hwModule->methods->open(hwModule, name,
            reinterpret_cast<hw_device_t**>(&lightDevice));    //将二级指针&lightDevice传给hal层
        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;
    }
}

ILight* HIDL_FETCH_ILight(const char* /* name */) {  //HIDL直通式
    std::map<Type, light_device_t*> lights;

    for(auto const &pair : kLogicalLights) {  //遍历所有的light type
        Type type = pair.first;
        const char* name = pair.second;

        light_device_tlight = 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 new Light(std::move(lights));
}

} // namespace implementation
}  // namespace V2_0
}  // namespace light
}  // namespace hardware
}  // namespace android

HAL:

/vendor/mediatek/proprietary/hardware/liblights/Android.mk

LOCAL_PATH:= $(call my-dir)

# HAL module implemenation, not prelinked and stored in

# hw/<COPYPIX_HARDWARE_MODULE_ID>.<ro.board.platform>.so

include $(CLEAR_VARS)

LOCAL_HEADER_LIBRARIES := libhardware_headers

LOCAL_MULTILIB := both

LOCAL_MODULE_TAGS := optional

LOCAL_PRELINK_MODULE := false

LOCAL_MODULE_RELATIVE_PATH := hw

LOCAL_SHARED_LIBRARIES := liblog

LOCAL_MODULE := lights.$(TARGET_BOARD_PLATFORM)

LOCAL_PROPRIETARY_MODULE := true

LOCAL_MODULE_OWNER := mtk

include $(MTK_SHARED_LIBRARY)

include $(call all-makefiles-under, $(LOCAL_PATH))

./tb8321p3_bsp/vendor/lib/hw/lights.mt6580.so

./tb8321p3_bsp/symbols/vendor/lib/hw/lights.mt6580.so

 /hardware/libhardware/include/hardware/lights.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

/*
 * These light IDs correspond to logical lights, not physical.
 * So for example, if your INDICATOR light is in line with your
 * BUTTONS, it might make sense to also light the INDICATOR
 * light to a reasonable color when the BUTTONS are lit.
 */
#define LIGHT_ID_BACKLIGHT          "backlight"
#define LIGHT_ID_KEYBOARD           "keyboard"
#define LIGHT_ID_BUTTONS            "buttons"
#define LIGHT_ID_BATTERY            "battery"
#define LIGHT_ID_NOTIFICATIONS      "notifications"
#define LIGHT_ID_ATTENTION          "attention"

struct light_device_t {
    struct hw_device_t common;

    /**
    * Set the provided lights to the provided values.
    *
    * Returns: 0 on succes, error code on failure.
    */
    int (*set_light)(struct light_device_t* dev,
            struct light_state_t const* state);
};

 /vendor/mediatek/proprietary/hardware/liblights/lights.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95

#define LOG_TAG "lights"
#include <hardware/lights.h>  //jni也include了这个(jni->hal)、hidl也include了这个(jni->hidl->hal)
... ...
/* LCD BACKLIGHT */
char const*const LCD_FILE
        = "/sys/class/leds/lcd-backlight/brightness";
... ...


/** Open a new instance of a lights device using name */
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_BACKLIGHTname)) {
        set_light = set_light_backlight;
        if (access(LCD_FILE, F_OK) < 0)
            return -errno;
    }
    else if (0 == strcmp(LIGHT_ID_KEYBOARD, name)) {
        set_light = set_light_keyboard;
        if (access(KEYBOARD_FILE, F_OK) < 0)
            return -errno;
    }
    else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) {
        set_light = set_light_buttons;
        if (access(BUTTON_FILE, F_OK) < 0)
            return -errno;
    }
    else if (0 == strcmp(LIGHT_ID_BATTERY, name)) {
        set_light = set_light_battery;
        if (access(RED_LED_FILE, F_OK) < 0)
            return -errno;
        if (access(GREEN_LED_FILE, F_OK) < 0)
            return -errno;
        if (access(BLUE_LED_FILE, F_OK) < 0)
            return -errno;
    }
    else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) {
        set_light = set_light_notifications;
        if (access(RED_LED_FILE, F_OK) < 0)
            return -errno;
        if (access(GREEN_LED_FILE, F_OK) < 0)
            return -errno;
        if (access(BLUE_LED_FILE, F_OK) < 0)
            return -errno;
    }
    else if (0 == strcmp(LIGHT_ID_ATTENTION, name)) {
        set_light = set_light_attention;
        if (access(RED_LED_FILE, F_OK) < 0)
            return -errno;
        if (access(GREEN_LED_FILE, F_OK) < 0)
            return -errno;
        if (access(BLUE_LED_FILE, F_OK) < 0)
            return -errno;
    }
    else {
        return -EINVAL;
    }

    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; //将jni或者hidl传进来的二级指针赋值为具体的函数指针
    return 0;
}


static struct hw_module_methods_t lights_module_methods = {
    .open =  open_lights,
};

/*
 * The lights Module
 */
struct hw_module_t HAL_MODULE_INFO_SYM = {
    .tag = HARDWARE_MODULE_TAG,
    //.version_major = 1,
    //.version_minor = 0,
    .id = LIGHTS_HARDWARE_MODULE_ID,
    .name = "MTK lights Module",
    .author = "MediaTek",
    .methods = &lights_module_methods,
};

 /vendor/mediatek/proprietary/hardware/liblights/lights.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

static int write_int(char const* path, int value)
{
    int fd;

#ifdef LIGHTS_INFO_ON
    ALOGD("write %d to %s", value, path);
#endif

    fd = open(path, O_RDWR);
    ALOGD("write_int open fd=%d\n", fd);
    if (fd >= 0) {
        char buffer[20];
        int bytes = sprintf(buffer, "%d\n", value);
        int amt = write(fd, buffer, bytes);
        close(fd);
        return amt == -1 ? -errno : 0;
    } else {
        return -errno;
    }
}

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);
    pthread_mutex_lock(&g_lock);
    g_backlight = brightness;
    err = write_int(LCD_FILE, brightness);
    if (g_haveTrackballLight) {
        handle_trackball_light_locked(dev);
    }
    pthread_mutex_unlock(&g_lock);
    return err;
}

二、通过aidl的方式:

 /hardware/interfaces/light/aidl/android/hardware/light/ILights.aidl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

package android.hardware.light;

import android.hardware.light.HwLightState;
import android.hardware.light.HwLight;

/**
 * Allows controlling logical lights/indicators, mapped to LEDs in a
 * hardware-specific manner by the HAL implementation.
 */
@VintfStability
interface ILights {
    /**
     * Set light identified by id to the provided state.
     *
     * If control over an invalid light is requested, this method exists with
     * EX_UNSUPPORTED_OPERATION. Control over supported lights is done on a
     * device-specific best-effort basis and unsupported sub-features will not
     * be reported.
     *
     * @param id ID of logical light to set as returned by getLights()
     * @param state describes what the light should look like.
     */
    void setLightState(in int id, in HwLightState state);

    /**
     * Discover what lights are supported by the HAL implementation.
     *
     * @return List of available lights
     */
    HwLight[] getLights();
}

 /vendor/mediatek/proprietary/hardware/liblights/aidl/default/Android.bp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

cc_binary {
    name: "android.hardware.lights-service.mediatek",
    relative_install_path: "hw",
    init_rc: ["lights-mtk-default.rc"],
    vintf_fragments: ["lights-mtk-default.xml"],
    vendor: true,
    shared_libs: [
        "libbase",
        "libutils",
        "liblog",
        "libbinder_ndk",
        "android.hardware.light-ndk_platform",
        "libhardware",
        "libhardware_legacy",
    ],
    srcs: [
        "Lights.cpp",
        "main.cpp",  #ABinderProcess_joinThreadPool();
    ],
}

androidgroup04@androidgroup04:~/disk00/Isaac/MT8168_alps-mp-r0.mp5/alps/out/target/product/tb8168p1_64_bsp$ find -name "*android.hardware.lights-service.mediatek*"

./vendor/bin/hw/android.hardware.lights-service.mediatek

./obj/EXECUTABLES/android.hardware.lights-service.mediatek_intermediates

./obj/EXECUTABLES/android.hardware.lights-service.mediatek_intermediates/android.hardware.lights-service.mediatek

./obj/PACKAGING/vendor_target_files_intermediates/vnd_tb8168p1_64_bsp-vendor_target_files-mp5V4381/VENDOR/bin/hw/android.hardware.lights-service.mediatek

./symbols/vendor/bin/hw/android.hardware.lights-service.mediatek

 /vendor/mediatek/proprietary/hardware/liblights/aidl/default/Lights.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67

#include "Lights.h"

namespace aidl {
namespace android {
namespace hardware {
namespace light {

using ::aidl::android::hardware::light::BnLights;
using ::aidl::android::hardware::light::HwLight;
using ::aidl::android::hardware::light::HwLightState;
using ::aidl::android::hardware::light::ILights;
using ::aidl::android::hardware::light::LightType;
using ::aidl::android::hardware::light::FlashMode;
... ...
ndk::ScopedAStatus Lights::setLightState(int id, const HwLightState& state) {

#ifdef LIGHTS_INFO_ON
    ALOGD("Lights setting state for id=%d, color=%0x\n",
            id, state.color);
#endif
    if (!(0 <= id && id < availableLights.size())) {
        ALOGI("Lights id %d does not exist.", id);
        return ndk::ScopedAStatus::fromExceptionCode(EX_UNSUPPORTED_OPERATION);
      }

    //int const color = rgbToBrightness(state.color);
    HwLight const* light = &(availableLights[id]);

    int ret = 0;

    switch (light->type) {
        case LightType::BACKLIGHT:
            ret = set_light_backlight(light, &state);
            break;
        case LightType::KEYBOARD:
            ret = set_light_keyboard(light, &state);
            break;
        case LightType::BUTTONS:
            ret = set_light_buttons(light, &state);
            break;
        case LightType::BATTERY:
            ret = set_light_battery(light, &state);
            break;
        case LightType::NOTIFICATIONS:
            ret = set_light_notifications(light, &state);
            break;
        case LightType::ATTENTION:
            ret = set_light_attention(light, &state);
            break;
        default:
            return ndk::ScopedAStatus::fromServiceSpecificError(EX_UNSUPPORTED_OPERATION);
    }
    switch (ret) {
        case -ENXIO:
            ALOGI("Lights id %d return %d.", id, ret);
        case 0:
            return ndk::ScopedAStatus::ok();
        default:
            ALOGI("Lights id %d return %d.", id, ret);
            return ndk::ScopedAStatus::fromServiceSpecificError(EX_UNSUPPORTED_OPERATION);
    }
}

}  // namespace light
}  // namespace hardware
}  // namespace android
}  // namespace aidl

 /vendor/mediatek/proprietary/hardware/liblights/aidl/default/Lights.h

1
2
3

/* LCD BACKLIGHT */
char const*const LCD_FILE
        = "/sys/class/leds/lcd-backlight/brightness";

 /vendor/mediatek/proprietary/hardware/liblights/aidl/default/Lights.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

static int
set_light_backlight(HwLight const* light, HwLightState const* state)
{
    if(!light) {
         return -1;
    }

    int err = 0;
    int brightness = rgb_to_brightness(state);
    if (!device_exists(LCD_FILE)) {
        return -ENXIO;
    }
#ifdef LIGHTS_INFO_ON
    ALOGD("set_light_backlight, level=%d, onMS=%d, offMS=%d\n",
        brightness, state->flashOnMs, state->flashOffMs);
#endif

    pthread_mutex_lock(&g_lock);
    g_backlight = brightness;
    err = write_int(LCD_FILEbrightness);
    if (g_haveTrackballLight) {
        handle_trackball_light_locked(light, state);
    }
    pthread_mutex_unlock(&g_lock);
    return err;
}

 /vendor/mediatek/proprietary/hardware/liblights/aidl/default/Lights.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

static int write_int(char const* path, int value)
{
    int fd = -1, ret = 0;

#ifdef LIGHTS_DBG_ON
    ALOGD("write %d to %s", value, path);
#endif

    fd = open(path, O_RDWR);
    if (fd >= 0) {
        char buffer[20];
        int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);  //将背光亮度格式化为字符串保存在buffer,返回字符串长度
        if (bytes >= sizeof(buffer)) {
            ret = -EINVAL;
            ALOGE("write error1 %d to %s, ret=%d", value, path, ret);
        } else {
            int amt = write(fdbuffer, bytes);  //往节点写数据
            ret = (amt == -1 ? -errno : 0);
        }
        close(fd);
        fd = -1;
    } else {
        ret = -errno;
        ALOGE("write %d to %s, result: %d", value, path, ret);
    }
    ALOGD("write %d to %s, result: %d", value, path, ret);
    return ret;
}

==================================================================

猜你喜欢

转载自blog.csdn.net/xiaowang_lj/article/details/132118138
MTK
今日推荐