Android HAL调用流程
来源:互联网 发布:oracle sql% 编辑:程序博客网 时间:2024/06/06 07:39
此文目前为半半半成品,待完善。
本文以light为例,分析android调用底层驱动的流程,今天先从LightsService开始,应用的调用部分后面再补充。
平台:rk3128
android版本:android 5.1
内核版本:3.10
一、LightsService服务
源码路径:frameworks/base/services/core/java/com/android/server/lights/LightsService.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 com.android.server.SystemService;import android.content.Context;import android.content.pm.PackageManager;import android.os.Handler;import android.os.IHardwareService;import android.os.Message;import android.os.Trace;import android.util.Slog;import java.io.FileInputStream;import java.io.FileOutputStream;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 LightImpl(int id) { mId = id; } @Override public void setBrightness(int brightness) { setBrightness(brightness, BRIGHTNESS_MODE_USER); } @Override public void setBrightness(int brightness, int brightnessMode) { synchronized (this) { 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); } } 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 (color != mColor || mode != mMode || onMS != mOnMS || offMS != mOffMS) { if (DEBUG) Slog.v(TAG, "setLight #" + mId + ": color=#" + Integer.toHexString(color)); mColor = color; mMode = mode; mOnMS = onMS; mOffMS = offMS; Trace.traceBegin(Trace.TRACE_TAG_POWER, "setLight(" + mId + ", " + color + ")"); try { setLight_native(mNativePointer, mId, color, mode, onMS, offMS, brightnessMode);//此处调用jni } finally { Trace.traceEnd(Trace.TRACE_TAG_POWER); } } } private int mId; private int mColor; private int mMode; private int mOnMS; private int mOffMS; private boolean mFlashing; } /* This class implements an obsolete API that was removed after eclair and re-added during the * final moments of the froyo release to support flashlight apps that had been using the private * IHardwareService API. This is expected to go away in the next release. */ private final IHardwareService.Stub mLegacyFlashlightHack = new IHardwareService.Stub() { private static final String FLASHLIGHT_FILE = "/sys/class/leds/spotlight/brightness"; public boolean getFlashlightEnabled() { try { FileInputStream fis = new FileInputStream(FLASHLIGHT_FILE); int result = fis.read(); fis.close(); return (result != '0'); } catch (Exception e) { return false; } } public void setFlashlightEnabled(boolean on) { final Context context = getContext(); if (context.checkCallingOrSelfPermission(android.Manifest.permission.FLASHLIGHT) != PackageManager.PERMISSION_GRANTED && context.checkCallingOrSelfPermission(android.Manifest.permission.HARDWARE_TEST) != PackageManager.PERMISSION_GRANTED) { throw new SecurityException("Requires FLASHLIGHT or HARDWARE_TEST permission"); } try { FileOutputStream fos = new FileOutputStream(FLASHLIGHT_FILE); byte[] bytes = new byte[2]; bytes[0] = (byte)(on ? '1' : '0'); bytes[1] = '\n'; fos.write(bytes); fos.close(); } catch (Exception e) { // fail silently } } }; public LightsService(Context context) { super(context); mNativePointer = init_native();//jni方法 for (int i = 0; i < LightsManager.LIGHT_ID_COUNT; i++) { mLights[i] = new LightImpl(i); } } @Override public void onStart() { publishBinderService("hardware", mLegacyFlashlightHack); publishLocalService(LightsManager.class, mService); } private final LightsManager mService = new LightsManager() { @Override public com.android.server.lights.Light getLight(int id) { if (id < LIGHT_ID_COUNT) { return mLights[id]; } else { return null; } } }; @Override protected void finalize() throws Throwable { finalize_native(mNativePointer); super.finalize(); } private Handler mH = new Handler() { @Override public void handleMessage(Message msg) { LightImpl light = (LightImpl)msg.obj; light.stopFlashing(); } }; private static native long init_native(); private static native void finalize_native(long ptr); static native void setLight_native(long ptr, int light, int color, int mode, int onMS, int offMS, int brightnessMode); private long mNativePointer;}接下来看jni的实现
frameworks/base/services/core/jni/com_android_server_lights_LightsService.cpp
/* * 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> //hal头文件#include <hardware/lights.h>#include <stdio.h>namespace android{// These values must correspond with the LIGHT_ID constants in// LightsService.javaenum { 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);//调用hal层接口,打开设备文件 if (err == 0) { return (light_device_t*)device; } 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);//调用hal,传入的参数是设备ID和module的地址 if (err == 0) { devices->lights[LIGHT_INDEX_BACKLIGHT] = get_device(module, LIGHT_ID_BACKLIGHT); 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 ; } memset(&state, 0, sizeof(light_state_t)); 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); }}//jni方法,供上层调用static 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));}};再看hal层代码
hardware/libhardware/hardware.c
/* * 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. */#include <hardware/hardware.h>#include <cutils/properties.h>#include <dlfcn.h>#include <string.h>#include <pthread.h>#include <errno.h>#include <limits.h>#define LOG_TAG "HAL"#include <utils/Log.h>/** Base path of the hal modules */#if defined(__LP64__)#define HAL_LIBRARY_PATH1 "/system/lib64/hw"#define HAL_LIBRARY_PATH2 "/vendor/lib64/hw"#else#define HAL_LIBRARY_PATH1 "/system/lib/hw"#define HAL_LIBRARY_PATH2 "/vendor/lib/hw"#endif/** * There are a set of variant filename for modules. The form of the filename * is "<MODULE_ID>.variant.so" so for the led module the Dream variants * of base "ro.product.board", "ro.board.platform" and "ro.arch" would be: * * led.trout.so * led.msm7k.so * led.ARMV6.so * led.default.so */static const char *variant_keys[] = { "ro.hardware", /* This goes first so that it can pick up a different file on the emulator. */ "ro.product.board", "ro.board.platform", "ro.arch"};static const int HAL_VARIANT_KEYS_COUNT = (sizeof(variant_keys)/sizeof(variant_keys[0]));/** * Load the file defined by the variant and if successful * return the dlopen handle and the hmi. * @return 0 = success, !0 = failure. *///这里就是加载lights.rk312x.sostatic int load(const char *id, const char *path, const struct hw_module_t **pHmi){ int status; void *handle; struct hw_module_t *hmi; /* * load the symbols resolving undefined symbols before * dlopen returns. Since RTLD_GLOBAL is not or'd in with * RTLD_NOW the external symbols will not be global */ handle = dlopen(path, RTLD_NOW); if (handle == NULL) { char const *err_str = dlerror(); ALOGE("load: module=%s\n%s", path, err_str?err_str:"unknown"); status = -EINVAL; goto done; } /* Get the address of the struct hal_module_info. */ const char *sym = HAL_MODULE_INFO_SYM_AS_STR; hmi = (struct hw_module_t *)dlsym(handle, sym); if (hmi == NULL) { ALOGE("load: couldn't find symbol %s", sym); status = -EINVAL; goto done; } /* Check that the id matches */ if (strcmp(id, hmi->id) != 0) { ALOGE("load: id=%s != hmi->id=%s", id, hmi->id); status = -EINVAL; goto done; } hmi->dso = handle; /* success */ status = 0; done: if (status != 0) { hmi = NULL; if (handle != NULL) { dlclose(handle); handle = NULL; } } else { ALOGV("loaded HAL id=%s path=%s hmi=%p handle=%p", id, path, *pHmi, handle); } *pHmi = hmi; return status;}/* * Check if a HAL with given name and subname exists, if so return 0, otherwise * otherwise return negative. On success path will contain the path to the HAL. */static int hw_module_exists(char *path, size_t path_len, const char *name, const char *subname){ snprintf(path, path_len, "%s/%s.%s.so", HAL_LIBRARY_PATH2, name, subname); if (access(path, R_OK) == 0) return 0; snprintf(path, path_len, "%s/%s.%s.so", HAL_LIBRARY_PATH1, name, subname); if (access(path, R_OK) == 0) return 0; return -ENOENT;}//根据class_id来找到hw module,这里仍然有疑问,在瑞芯微平台,light对应的模块名应为lights.rk312x.so,//但在variant_keys中并没有这个选项,也不是default,所以是怎么找到lights.rk312x.so并load进来的?留作以后研究int hw_get_module_by_class(const char *class_id, const char *inst, const struct hw_module_t **module){ int i; char prop[PATH_MAX]; char path[PATH_MAX]; char name[PATH_MAX]; char prop_name[PATH_MAX]; if (inst) snprintf(name, PATH_MAX, "%s.%s", class_id, inst); else strlcpy(name, class_id, PATH_MAX); /* * Here we rely on the fact that calling dlopen multiple times on * the same .so will simply increment a refcount (and not load * a new copy of the library). * We also assume that dlopen() is thread-safe. */ /* First try a property specific to the class and possibly instance */ snprintf(prop_name, sizeof(prop_name), "ro.hardware.%s", name); if (property_get(prop_name, prop, NULL) > 0) { if (hw_module_exists(path, sizeof(path), name, prop) == 0) { goto found; } } /* Loop through the configuration variants looking for a module */ for (i=0 ; i<HAL_VARIANT_KEYS_COUNT; i++) { if (property_get(variant_keys[i], prop, NULL) == 0) { continue; } if (hw_module_exists(path, sizeof(path), name, prop) == 0) { goto found; } } /* Nothing found, try the default */ if (hw_module_exists(path, sizeof(path), name, "default") == 0) { goto found; } return -ENOENT;found: /* load the module, if this fails, we're doomed, and we should not try * to load a different variant. */ return load(class_id, path, module);}//jni的init_native函数会调用这个函数int hw_get_module(const char *id, const struct hw_module_t **module){ return hw_get_module_by_class(id, NULL, module);}
hardware/rockchip/liblights/lights.cpp
/******************************************************************//*Copyright (C) ROCK-CHIPS FUZHOU . All Rights Reserved. *//******************************************************************* * File : lights.cpp * Desc : Implement lights adjust HAL * Author : CMY * Date : 2009-07-22 * Notes : .............. * * Revision 1.00 2009/07/22 CMY * Revision 2.00 2012/01/08 yxj * support button charge lights * * ................... * ********************************************************************/#define LOG_TAG "Lights"//#include <hardware/hardware.h>//#include <hardware/lights.h>#include "lights.h"#include <fcntl.h>#include <errno.h>#include <cutils/atomic.h>/*****************************************************************************/#define BACKLIGHT_PATH"/sys/class/backlight/rk28_bl/brightness"#define BUTTON_LED_PATH "sys/class/leds/rk29_key_led/brightness"#define BATTERY_LED_PATH "sys/class/leds/battery_led/brightness"int g_bl_fd = 0; //backlight fdint g_btn_fd = 0; //button light fdint g_bat_fd = 0; //battery charger fdstatic pthread_once_t g_init = PTHREAD_ONCE_INIT;static pthread_mutex_t g_lock = PTHREAD_MUTEX_INITIALIZER;static int light_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device);static struct hw_module_methods_t light_module_methods = { open: light_device_open};/*注册一个硬件对象,即Light Stublight_module_t定义如下:struct light_module_t { struct hw_module_t common;};每个硬件模块都必须有一个名为HAL_MODULE_INFO_SYM的数据结构并且此数据结构的字段必须以hw_module_t开头其次是模块具体信息*/struct light_module_t HAL_MODULE_INFO_SYM = { common: {//初始化父结构体即hw_module_t成员 tag: HARDWARE_MODULE_TAG,//TAG必须为HARDWARE_MODULE_TAG version_major: 1,//主版本号 version_minor: 0,//次版本号 id: LIGHTS_HARDWARE_MODULE_ID,//硬件ID,就是通过这个ID找到对应的硬件设备的 name: "Lights module",//硬件module名字 author: "Rockchip",//作者 methods: &light_module_methods,//指向封装有open函数指针的结构体 } //如果有扩展属性,在此处初始化};static void init_g_lock(void){pthread_mutex_init(&g_lock, NULL);}static int write_int(char const *path, int value){int fd;static int already_warned;already_warned = 0;LOGV("write_int: path %s, value %d", path, value);fd = open(path, O_RDWR);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 {if (already_warned == 0) {LOGE("write_int failed to open %s\n", path);already_warned = 1;}return -errno;}}static int rgb_to_brightness(struct light_state_t const *state){unsigned int color = state->color;unsigned char brightness = ((77*((color>>16)&0x00ff)) + (150*((color>>8)&0x00ff)) + (29*(color&0x00ff))) >> 8;return brightness;}int set_backlight_light(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);err = write_int(BACKLIGHT_PATH, brightness);pthread_mutex_unlock(&g_lock);return 0;}int set_keyboard_light(struct light_device_t* dev, struct light_state_t const* state){LOGI(">>> Enter set_keyboard_light");return 0;}int set_buttons_light(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);err = write_int(BUTTON_LED_PATH, brightness?1:0);pthread_mutex_unlock(&g_lock);return 0;}int set_battery_light(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);err = write_int(BATTERY_LED_PATH, brightness?1:0);pthread_mutex_unlock(&g_lock);return 0;}int set_notifications_light(struct light_device_t* dev, struct light_state_t const* state){LOGI(">>> Enter set_notifications_light");return 0;}int set_attention_light(struct light_device_t* dev, struct light_state_t const* state){LOGI(">>> Enter set_attention_light");return 0;}static int light_device_close(struct hw_device_t *dev) { struct light_device_t* ctx = (struct light_device_t*)dev;LOGI(">>> Enter light_device_close"); if (ctx)free(ctx); return 0;}//打开设备static int light_device_open(const struct hw_module_t* module, const char* name, struct hw_device_t** device){ int status = 0;LOGI(">>> Enter light_device_open:%s\n",name); struct light_device_t *dev; dev = (light_device_t*)malloc(sizeof(*dev)); /* initialize our state here */ memset(dev, 0, sizeof(*dev));/*填充light_device_t结构体定义:struct light_device_t { struct hw_device_t common; int (*set_light)(struct light_device_t* dev, struct light_state_t const* state);};light_device_t“继承”自hw_device_t,并且扩展了自己的函数set_light*/ /* initialize the procs */ dev->common.tag = HARDWARE_DEVICE_TAG; dev->common.version = 0; dev->common.module = const_cast<hw_module_t*>(module); dev->common.close = light_device_close; *device = &dev->common; if (!strcmp(name, LIGHT_ID_BACKLIGHT)) { dev->set_light = set_backlight_light; }else if(!strcmp(name, LIGHT_ID_KEYBOARD)) { dev->set_light = set_keyboard_light; }else if(!strcmp(name, LIGHT_ID_BUTTONS)) { dev->set_light = set_buttons_light; }else if(!strcmp(name, LIGHT_ID_BATTERY)) { dev->set_light = set_battery_light; }else if(!strcmp(name, LIGHT_ID_NOTIFICATIONS)) { dev->set_light = set_notifications_light; }else if(!strcmp(name, LIGHT_ID_ATTENTION)) { dev->set_light = set_attention_light; }else{ LOGI(">>> undefine light id"); free(dev); *device = NULL; status = -EINVAL;} pthread_once(&g_init,init_g_lock); return status;}
接下来先看下初始化流程:
LightsService构造方法->init_native(jni)->hw_get_module(hal)->hw_get_module_by_class->load ,这里相当于初始化的过程,主要是传入模块ID,根据模块ID加载对应的so库。并且根据硬件ID即LIGHTS_HARDWARE_MODULE_ID找到我们注册的结构体。
然后再回到init_native(jni)->get_device->module->methods->open(module, name, &device);这里调用到light.cpp中light_device_open,在light_device_open中根据open的第二个参数确定light的类型并绑定到dev->set_light。
再看调节过程:
setBrightness->setLightLocked(android)->setLight_native(jni)->devices->lights[light]->set_light(devices->lights[light], &state); set_light在上一步中已经绑定。
以set_buttons_light为例的话,最终会通过write_int直接调用设备驱动文件。从而能对硬件进行操作。
- Android HAL调用流程
- Android HAL的被调用流程
- Android HAL的被调用流程
- Android HAL的被调用流程
- Android HAL的被调用流程
- Android HAL的被调用流程
- Android HAL的被调用流程
- Android HAL的被调用流程
- Android Camera AP到Camera Hal调用流程
- Android Camera FW到Camera Hal调用流程
- Android Camera AP到Camera Hal调用流程
- Android 怎么样调用HAL的
- Android HAL介绍及调用
- Android之Camera拍照插值算法 &&Android4.2之Camera系统HAL调用流程
- Android AudioFlinger加载HAL层流程
- Android HAL 是如何被调用的
- Android HAL 是如何被调用的
- Android HAL 是如何被调用的
- 多条件查询的两种实现方式
- arcmap操作Excel文件没有注册类解决办法
- 这次机会,我会用120分的努力来把握!
- 快速学习Javascript初级知识
- grep 后加单引号、双引号和不加引号的区别
- Android HAL调用流程
- C++字符串
- cp 拷贝文件的时间
- vue data: { eventHub: new Vue() }
- java.lang.IllegalArgumentException: node to traverse cannot be null!
- 手机访问本地开发web页面(http-server的配置)
- Android直播解决方案——非常具有参考意义
- (补题心路)——“盛大游戏杯”第15届上海大学程序设计联赛夏季赛暨上海高校金马五校赛
- deep learning 自学习网络的Softmax分类器