Android灯光系统(硬件访问服务框架)
16lz
2021-12-09
Android灯光系统(硬件访问服务框架)
Java类:LightsService.java
LightsService.java通过调用,LightsService JNI来实现com.android.server包中的LightsService类。
这个类不是平台API,被Android系统JAVA框架中的其他一些部分调用。
/* * Copyright (C) 2008 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. */package com.android.server.lights;import android.app.ActivityManager;import android.content.Context;import android.os.Handler;import android.os.IBinder;import android.os.Message;import android.os.PowerManager;import android.os.Trace;import android.provider.Settings;import android.util.Slog;import android.view.SurfaceControl;import com.android.server.SystemService;public class LightsService extends SystemService { static final String TAG = "LightsService"; static final boolean DEBUG = false; final LightImpl mLights[] = new LightImpl[LightsManager.LIGHT_ID_COUNT]; private final class LightImpl extends Light { private final IBinder mDisplayToken; private final int mSurfaceControlMaximumBrightness; private LightImpl(Context context, int id) { mId = id; mDisplayToken = SurfaceControl.getInternalDisplayToken(); final boolean brightnessSupport = SurfaceControl.getDisplayBrightnessSupport( mDisplayToken); if (DEBUG) { Slog.d(TAG, "Display brightness support: " + brightnessSupport); } int maximumBrightness = 0; if (brightnessSupport) { PowerManager pm = context.getSystemService(PowerManager.class); if (pm != null) { maximumBrightness = pm.getMaximumScreenBrightnessSetting(); } } mSurfaceControlMaximumBrightness = maximumBrightness; } @Override public void setBrightness(int brightness) { setBrightness(brightness, BRIGHTNESS_MODE_USER); } @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; } // 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) { // 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, (float) brightness / mSurfaceControlMaximumBrightness); } else { int color = brightness & 0x000000ff; color = 0xff000000 | (color << 16) | (color << 8) | color; setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, brightnessMode); } } } @Override public void setColor(int color) { synchronized (this) { setLightLocked(color, LIGHT_FLASH_NONE, 0, 0, 0); } } @Override public void setFlashing(int color, int mode, int onMS, int offMS) { synchronized (this) { setLightLocked(color, mode, onMS, offMS, BRIGHTNESS_MODE_USER); } } @Override public void pulse() { pulse(0x00ffffff, 7); } @Override public void pulse(int color, int onMS) { synchronized (this) { if (mColor == 0 && !mFlashing) { setLightLocked(color, LIGHT_FLASH_HARDWARE, onMS, 1000, BRIGHTNESS_MODE_USER); mColor = 0; mH.sendMessageDelayed(Message.obtain(mH, 1, this), onMS); } } } @Override public void turnOff() { synchronized (this) { setLightLocked(0, LIGHT_FLASH_NONE, 0, 0, 0); } } @Override public void setVrMode(boolean enabled) { synchronized (this) { if (mVrModeEnabled != enabled) { mVrModeEnabled = enabled; mUseLowPersistenceForVR = (getVrDisplayMode() == Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE); if (shouldBeInLowPersistenceMode()) { mLastBrightnessMode = mBrightnessMode; } // NOTE: We do not trigger a call to setLightLocked here. We do not know the // current brightness or other values when leaving VR so we avoid any incorrect // jumps. The code that calls this method will immediately issue a brightness // update which is when the change will occur. } } } private void stopFlashing() { synchronized (this) { setLightLocked(mColor, LIGHT_FLASH_NONE, 0, 0, BRIGHTNESS_MODE_USER); } } 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 #" + mId + ": color=#" + Integer.toHexString(color) + ": brightnessMode=" + brightnessMode); mInitialized = true; mLastColor = mColor; mColor = color; mMode = mode; mOnMS = onMS; mOffMS = offMS; mBrightnessMode = brightnessMode; Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", 0x" + Integer.toHexString(color) + ")"); try { setLight_native(mId, color, mode, onMS, offMS, brightnessMode); } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); } } } private boolean shouldBeInLowPersistenceMode() { return mVrModeEnabled && mUseLowPersistenceForVR; } private int mId; private int mColor; private int mMode; private int mOnMS; private int mOffMS; private boolean mFlashing; private int mBrightnessMode; private int mLastBrightnessMode; private int mLastColor; private boolean mVrModeEnabled; private boolean mUseLowPersistenceForVR; private boolean mInitialized; } public LightsService(Context context) { super(context); for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) { mLights[i] = new LightImpl(context, i); } } @Override public void onStart() { publishLocalService(LightsManager.class, mService); } @Override public void onBootPhase(int phase) { } private int getVrDisplayMode() { int currentUser = ActivityManager.getCurrentUser(); return Settings.Secure.getIntForUser(getContext().getContentResolver(), Settings.Secure.VR_DISPLAY_MODE, /*default*/Settings.Secure.VR_DISPLAY_MODE_LOW_PERSISTENCE, currentUser); } 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; } } }; private Handler mH = new Handler() { @Override public void handleMessage(Message msg) { LightImpl light = (LightImpl)msg.obj; light.stopFlashing(); } }; static native void setLight_native(int light, int color, int mode, int onMS, int offMS, int brightnessMode);}
本地类:com_android_server_lights_LightsService.cpp
这个类调用硬件抽象层,也同时提供了JNI的接口。
/* * 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 #include "android_runtime/AndroidRuntime.h"#include #include #include #include #include #include #include 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 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."); 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."); }}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(); 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));}};
硬件抽象层:light.c
/* * Copyright (C) 2008 The Android Open Source Project * Copyright (C) 2014 The Linux Foundation. All rights reserved. * * 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 #include #include #include #include #include #include #include #include #include #include #include #include /* * Change this to 1 to support battery notifications via BatteryService */#define LIGHTS_SUPPORT_BATTERY 0#define CG_COLOR_ID_PROPERTY "ro.boot.hardware.color"static pthread_once_t g_init = PTHREAD_ONCE_INIT;static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;static struct light_state_t g_notification;static struct light_state_t g_battery;static int g_last_backlight_mode = BRIGHTNESS_MODE_USER;static int g_attention = 0;static int rgb_brightness_ratio = 255;char const*const RED_LED_FILE = "/sys/class/leds/red/brightness";char const*const GREEN_LED_FILE = "/sys/class/leds/green/brightness";char const*const BLUE_LED_FILE = "/sys/class/leds/blue/brightness";char const*const LCD_FILE = "/sys/class/leds/lcd-backlight/brightness";char const*const PERSISTENCE_FILE = "/sys/class/leds/lcd-backlight/low_persistence";char const*const RED_BLINK_FILE = "/sys/class/leds/red/blink";char const*const GREEN_BLINK_FILE = "/sys/class/leds/green/blink";char const*const BLUE_BLINK_FILE = "/sys/class/leds/blue/blink";char const*const RED_ON_OFF_MS_FILE = "/sys/class/leds/red/on_off_ms";char const*const GREEN_ON_OFF_MS_FILE = "/sys/class/leds/green/on_off_ms";char const*const BLUE_ON_OFF_MS_FILE = "/sys/class/leds/blue/on_off_ms";char const*const RED_RGB_START_FILE = "/sys/class/leds/red/rgb_start";char const*const GREEN_RGB_START_FILE = "/sys/class/leds/green/rgb_start";char const*const BLUE_RGB_START_FILE = "/sys/class/leds/blue/rgb_start";/** * device methods */void init_globals(void){ char color_id_prop[PROPERTY_VALUE_MAX] = { ""}; // init the mutex pthread_mutex_init(&g_lock, NULL); // check CG color property_get(CG_COLOR_ID_PROPERTY, color_id_prop, "DEF00"); if (strcmp(color_id_prop, "GRA00") == 0) { rgb_brightness_ratio = 25; } else if (strcmp(color_id_prop, "SLV00") == 0) { rgb_brightness_ratio = 15; } else if (strcmp(color_id_prop, "BLU00") == 0) { rgb_brightness_ratio = 15; } else { rgb_brightness_ratio = 20; }}static intwrite_int(char const* path, int value){ int fd; static int already_warned = 0; fd = open(path, O_WRONLY); if (fd >= 0) { char buffer[20]; size_t bytes = snprintf(buffer, sizeof(buffer), "%d\n", value); if(bytes >= sizeof(buffer)) return -EINVAL; ssize_t amt = write(fd, buffer, bytes); close(fd); return amt == -1 ? -errno : 0; } else { if (already_warned == 0) { ALOGE("write_int failed to open %s\n", path); already_warned = 1; } return -errno; }}static intwrite_double_int(char const* path, int value1, int value2){ int fd; static int already_warned = 0; fd = open(path, O_WRONLY); if (fd >= 0) { char buffer[20]; size_t bytes = snprintf(buffer, sizeof(buffer), "%d %d\n", value1, value2); if(bytes >= sizeof(buffer)) return -EINVAL; ssize_t amt = write(fd, buffer, bytes); close(fd); return amt == -1 ? -errno : 0; } else { if (already_warned == 0) { ALOGE("write_int failed to open %s\n", path); already_warned = 1; } return -errno; }}static intis_lit(struct light_state_t const* state){ return state->color & 0x00ffffff;}static intrgb_to_brightness(struct light_state_t const* state){ int color = state->color & 0x00ffffff; return ((77*((color>>16)&0x00ff)) + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;}static intset_light_backlight(struct light_device_t* dev, struct light_state_t const* state){ int err = 0; int brightness = rgb_to_brightness(state); unsigned int lpEnabled = state->brightnessMode == BRIGHTNESS_MODE_LOW_PERSISTENCE; if(!dev) { return -1; } pthread_mutex_lock(&g_lock); // If we're not in lp mode and it has been enabled or if we are in lp mode // and it has been disabled send an ioctl to the display with the update if ((g_last_backlight_mode != state->brightnessMode && lpEnabled) || (!lpEnabled && g_last_backlight_mode == BRIGHTNESS_MODE_LOW_PERSISTENCE)) { if ((err = write_int(PERSISTENCE_FILE, lpEnabled)) != 0) { ALOGE("%s: Failed to write to %s: %s\n", __FUNCTION__, PERSISTENCE_FILE, strerror(errno)); } } g_last_backlight_mode = state->brightnessMode; if (!err) { err = write_int(LCD_FILE, brightness); } pthread_mutex_unlock(&g_lock); return err;}static intset_speaker_light_locked(struct light_device_t* dev, struct light_state_t const* state){ int red, green, blue; int blink; int onMS, offMS; unsigned int colorRGB; if(!dev) { return -1; } switch (state->flashMode) { case LIGHT_FLASH_TIMED: onMS = state->flashOnMS; offMS = state->flashOffMS; break; case LIGHT_FLASH_NONE: default: onMS = 0; offMS = 0; break; } colorRGB = state->color;#if 0 ALOGD("set_speaker_light_locked mode %d, colorRGB=%08X, onMS=%d, offMS=%d\n", state->flashMode, colorRGB, onMS, offMS);#endif red = ((colorRGB >> 16) & 0xFF) * rgb_brightness_ratio / 255; green = ((colorRGB >> 8) & 0xFF) * rgb_brightness_ratio / 255; blue = (colorRGB & 0xFF) * rgb_brightness_ratio / 255; write_double_int(RED_ON_OFF_MS_FILE, onMS, offMS); write_int(RED_LED_FILE, red); write_double_int(GREEN_ON_OFF_MS_FILE, onMS, offMS); write_int(GREEN_LED_FILE, green); write_double_int(BLUE_ON_OFF_MS_FILE, onMS, offMS); write_int(BLUE_LED_FILE, blue); if(!write_int(RED_RGB_START_FILE, 1)) if(!write_int(GREEN_RGB_START_FILE, 1)) if(!write_int(BLUE_RGB_START_FILE, 1)) return -1; return 0;}static voidhandle_speaker_battery_locked(struct light_device_t* dev){ if (is_lit(&g_battery)) { set_speaker_light_locked(dev, &g_battery); } else { set_speaker_light_locked(dev, &g_notification); }}#if LIGHTS_SUPPORT_BATTERYstatic intset_light_battery(struct light_device_t* dev, struct light_state_t const* state){ pthread_mutex_lock(&g_lock); g_battery = *state; handle_speaker_battery_locked(dev); pthread_mutex_unlock(&g_lock); return 0;}#endifstatic intset_light_notifications(struct light_device_t* dev, struct light_state_t const* state){ pthread_mutex_lock(&g_lock); g_notification = *state; handle_speaker_battery_locked(dev); pthread_mutex_unlock(&g_lock); return 0;}static intset_light_attention(struct light_device_t* dev, struct light_state_t const* state){ pthread_mutex_lock(&g_lock); if (state->flashMode == LIGHT_FLASH_HARDWARE) { g_attention = state->flashOnMS; } else if (state->flashMode == LIGHT_FLASH_NONE) { g_attention = 0; } handle_speaker_battery_locked(dev); pthread_mutex_unlock(&g_lock); return 0;}/** Close the lights device */static intclose_lights(struct light_device_t *dev){ if (dev) { free(dev); } return 0;}/******************************************************************************//** * 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)) set_light = set_light_backlight;#if LIGHTS_SUPPORT_BATTERY else if (0 == strcmp(LIGHT_ID_BATTERY, name)) set_light = set_light_battery;#endif else if (0 == strcmp(LIGHT_ID_NOTIFICATIONS, name)) set_light = set_light_notifications; 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;}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 = "lights Module", .author = "Google, Inc.", .methods = &lights_module_methods,};
驱动层:led_driver.c
#include #include #include #include #include #include #include #define PAD_LEDCON 0x01c208b4#define PAD_LEDDAT 0x01c208c4unsigned int *pad_con = NULL;unsigned int *pad_dat = NULL;struct led_classdev * cdev;void leds_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness){ if(brightness){ writel((readl(pad_dat)&(~(1<<2))),pad_dat);}else{ writel((readl(pad_dat)|(1<<2)),pad_dat);}}static int __init leds_init(void){ int ret;//1.分配结构体cdev = kzalloc(sizeof(*cdev),GFP_KERNEL);if(cdev == NULL){ printk("alloc led_classdev is fail.\n");return -ENOMEM;}//2.结构体的初始化cdev->name = "myleds";cdev->max_brightness = LED_FULL;cdev->brightness_set = leds_brightness_set;cdev->flags |= LED_CORE_SUSPENDRESUME;//3.硬件相关的操作pad_con = (unsigned int *)ioremap(PAD_LEDCON,4);pad_dat = (unsigned int *)ioremap(PAD_LEDDAT,4);writel(((readl(pad_con)&(~(0xf<<8)))|(1<<8)),pad_con);writel((readl(pad_dat)|(1<<2)),pad_dat);//4.注册ret = led_classdev_register(NULL,cdev);if(ret < 0){ printk("register led_classdev is fail.\n");return -EAGAIN;}return 0;}static void __exit leds_exit(void){ //注销led_classdev_unregister(cdev);}module_init(leds_init);module_exit(leds_exit);MODULE_LICENSE("GPL");
更多相关文章
- :activity状态的保存和保持
- Android(安卓) Intent 的几种启动活动的方式
- Lua学习 2) —— Android与Lua互调
- android api 中文 (75)—— AdapterView.OnItemClickListener
- Android四大基本组件介绍与生命周期
- Android消息机制不完全解析(上)
- Android(安卓)Retrofit 2.0框架上传图片,视频解决方案
- 2011.11.25——— android ndk 坑爹的cygwin
- Android调用系统短信发送界面并预设接收号码、短信内容