基于 Light 介绍安卓 8.0 HAL 变化

前言

学习笔记,简单介绍了 light 在 Android 8.0 上的整个调用流程

开始

一张图开场
基于 Light 介绍安卓 8.0 HAL 变化

插播下 Java Binder 服务编写框图:
基于 Light 介绍安卓 8.0 HAL 变化

C++ Binder 服务编写框图:
基于 Light 介绍安卓 8.0 HAL 变化

下面将从上到下介绍:

0.【Java 安卓LED服务类】LightsService.java

public class LightsService extends SystemService {
	
	// 下一级 Jni 接口
	static native void setLight_native(int light, int color, int mode,
        int onMS, int offMS, int brightnessMode);
}

1.【JNI 客户端实现】com_android_server_lights_LightsService.cpp

	static const JNINativeMethod method_table[] = {
	    { "setLight_native", "(IIIIII)V", (void*)setLight_native },
	};

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

2.【HIDL 客户】ILight.与 HIDL 服务库通信.hal

	定义了 HIDL 接口 
	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);
	
	};

3.【HIDL 客户】LightAll.cpp.调用 HIDL 服务库

::android::status_t BnHwLight::onTransact(
    uint32_t _hidl_code,
    const ::android::hardware::Parcel &_hidl_data,
    ::android::hardware::Parcel *_hidl_reply,
    uint32_t _hidl_flags,
    TransactCallback _hidl_cb)
			// 下一级接口
			Status _hidl_out_status = _hidl_mImpl->setLight(type, *state);

4.【HIDL 服务】android.hardware.light@2.0-service.启动注册 HIDL 服务库

	service light-hal-2-0 /vendor/bin/hw/android.hardware.light@2.0-service
	    class hal
	    user system
	    group system

4.【HIDL 服务】service.cpp.向上注册 HIDL 服务库

	int main() {
		    return defaultPassthroughServiceImplementation<ILight>();    
		            /////////////////////////////////////////////////////////////////////////
		            // LegacySupport.h (system\libhidl\transport\include\hidl)
		            defaultPassthroughServiceImplementation(std::string name, size_t maxThreads = 1)
		                configureRpcThreadpool(maxThreads, true);
		                    configureBinderRpcThreadpool(maxThreads, callerWillJoin);
		                        ProcessState::self()->setThreadPoolConfiguration(maxThreads, callerWillJoin /*callerJoinsPool*/);
		                    
		                    
		                status_t result = registerPassthroughServiceImplementation<Interface>(name);                                    
		                                    registerPassthroughServiceImplementation( std::string name = "default")
		                                            sp<Interface> service = Interface::getService(name, true /* getStub */);
		                                            status_t status = service->registerAsService(name);
		                                    
		                joinRpcThreadpool();
		                    joinBinderRpcThreadpool();
		                        IPCThreadState::self()->joinThreadPool();

5.【HIDL 服务】Light.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

6.【HIDL 服务】Light.cpp.加载调用传统库

	ILight* HIDL_FETCH_ILight(const char* /* name */) {
	   std::map<Type, light_device_t*> lights;
	
	    for(auto const &pair : kLogicalLights) {
	        Type type = pair.first;
	        const char* name = pair.second;
	
			// 加载传统 HAL 库 
	        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 new Light(std::move(lights));
	}


	Light::Light(std::map<Type, light_device_t*> &&lights)
	  : mLights(std::move(lights)) {}
	
	// Methods from ::android::hardware::light::V2_0::ILight follow.
	Return<Status> Light::setLight(Type type, const LightState& state)  {
	    auto it = mLights.find(type);
	
	    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;
	    }
	}	

7.【HAL 实现】lights.c.传统 HAL 库

	/*
	 * 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 = "lights Module",
	    .author = "Google, Inc.",
	    .methods = &lights_module_methods,
	};

/**
 * module methods
 */

/** 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_BACKLIGHT, name)) {
        char property[PROPERTY_VALUE_MAX];
        property_get("persist.extend.brightness", property, "0");

        if(!(strncmp(property, "1", PROPERTY_VALUE_MAX)) ||
           !(strncmp(property, "true", PROPERTY_VALUE_MAX))) {
            property_get("persist.display.max_brightness", property, "255");
            g_brightness_max = atoi(property);
            set_brightness_ext_init();
            set_light = set_light_backlight_ext;
        } else

			// 调用接口 set_light , 上层会调用到这里来
            set_light = set_light_backlight;
    } else if (0 == strcmp(LIGHT_ID_BATTERY, name))
        set_light = set_light_battery;
    else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name))
        set_light = set_light_notifications;
    else if (0 == strcmp(LIGHT_ID_BUTTONS, name)) {
        if (!access(BUTTON_FILE, F_OK)) {
          // enable light button when the file is present			  
          set_light = set_light_buttons;
        } else {
          return -EINVAL;
        }
    }
    else if (0 == strcmp(LIGHT_ID_ATTENTION, name))
        set_light = set_light_attention;
    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 = LIGHTS_DEVICE_API_VERSION_2_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;
}


# 更新灯则通过 sys/class/led/xxx/bright 来操作的
// char const*const RED_LED_FILE    = "/sys/class/leds/red/brightness";
set_speaker_light_locked(struct light_device_t* dev,
    struct light_state_t const* state)
		write_int(RED_LED_FILE, 0);
			int bytes = snprintf(buffer, sizeof(buffer), "%d\n", value);
    		ssize_t amt = write(fd, buffer, (size_t)bytes);

8.【内核实现】leds-qpnp.c

【充电 CHG_LED 可用红灯配置流程】:
	// Msm8937-pmi8940-mtp.dtsi (kernel\msm-3.18\arch\arm64\boot\dts\qcom)
	    &pmi8940_charger {
	        qcom,battery-data = <&mtp_batterydata>;
	        qcom,chg-led-sw-controls;
	        qcom,chg-led-support;
	    };
	
	    解析使用位置:Qpnp-smbcharger.c (kernel\msm-3.18\drivers\power)
	        static int __init smbchg_init(void)
	            // static struct spmi_driver smbchg_driver = {
	            //     .driver		= {
	            //         .name		= "qpnp-smbcharger",
	            //         .owner		= THIS_MODULE,
	            //         .of_match_table	= smbchg_match_table,
	            //         .pm		= &smbchg_pm_ops,
	            //     },
	            //     .probe		= smbchg_probe,
	            //     .remove		= smbchg_remove,
	            //     .shutdown	= smbchg_shutdown,
	            // };
	            return spmi_driver_register(&smbchg_driver);
	
	
	        smbchg_probe(struct spmi_device *spmi)
	            smb_parse_dt(struct smbchg_chip *chip)
	                chip->cfg_chg_led_support =	of_property_read_bool(node, "qcom,chg-led-support");
	                
	            。。。    
	            if (chip->cfg_chg_led_support && chip->schg_version == QPNP_SCHG_LITE)    
	                rc = smbchg_register_chg_led(chip);
	                        chip->led_cdev.name = "red";
	                        chip->led_cdev.brightness_set = smbchg_chg_led_brightness_set;
	                        chip->led_cdev.brightness_get = smbchg_chg_led_brightness_get;
	                        rc = led_classdev_register(chip->dev, &chip->led_cdev);
上一篇:2021-09-06


下一篇:环境光照水平 | @media.light-level (Media Queries) - CSS 中文开发手册 - Break易站