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直接调用设备驱动文件。从而能对硬件进行操作。

 
原创粉丝点击