分享

Android HAL技术详解

 dwlinux_gs 2014-07-19
第一部分:HAL层

hardware\led\include\Led.h

定义常见数据结构

struct led_module_t {

   struct hw_module_t common;

};



struct led_control_device_t {  

   struct hw_device_t common;  /*表示硬件设备*/

   /* 属性 */

   int fd;

   /* 提供出来的方法 */

   int (*set_on)(struct led_control_device_t *dev, int32_t led);

   int (*set_off)(struct led_control_device_t *dev, int32_t led);

};



nstruct led_control_context_t {

    struct led_control_device_t device;

};





hardware\led\led\Led.cpp 分析



static int led_device_open(const struct hw_module_t* module, const char* name,

        struct hw_device_t** device) 

{

    struct led_control_device_t *dev;

    /* 分配设备 */

    dev = (struct led_control_device_t *)malloc(sizeof(*dev));

    memset(dev, 0sizeof(*dev));



    dev->common.tag =  HARDWARE_DEVICE_TAG;

    dev->common.version = 0;

    dev->common.module = (struct hw_module_t*)module;  /*设置是属于哪个模块 */

    dev->common.close = led_device_close;

    

    dev->set_on = led_on{  

        /*自定义方法*/

        int led_off(struct led_control_device_t *dev, int32_t led)

        {

            ioctl(g_fd, 0, led); //led on

        }

    }

    dev->set_off = led_off;    /*自定义方法*/



    *device = &dev->common;

    /*

    /dev/leds0 内核驱动的device_create创建的

    假如打开设备时候发生:Hello Stub: failed to open /dev/leds0 -- Permission denied.

    进入到system/core/rootdir目录,里面有一个名为ueventd.rc文件,往里面添加一行:

     /dev/hello 0666 root leds0

    
*/

     g_fd = open("/dev/leds0"0);

    return 0;

}



/*模块方法表*/  

static struct hw_module_methods_t led_module_methods = {

    open: led_device_open

};

/*  

    模块信息 

    实例变量名必须为HAL_MODULE_INFO_SYM,

    tag也必须为HARDWARE_MODULE_TAG,这是Android硬件抽象层规范规定的。

*/

extern "C" ① const struct led_module_t HAL_MODULE_INFO_SYM = {

    common: {

        tag: HARDWARE_MODULE_TAG,  

        version_major: 1,

        version_minor: 0,

        id: LED_HARDWARE_MODULE_ID,

        name: "Sample LED Stub",

        author: "The Forlinx Open Source Project",

        methods: &led_module_methods,  /*设置方法  */

    }

    /* supporting APIs go here */

};



① extern "C" :C++编写的代码片段可能被使用在其它语言编写的代码中。不同语言编写的代码互相调用是困难的。

为了使它们遵守统一规则,可以使用extern指定一个编译和连接规约。extern "C"指令中的C,表示的一种编译和连接规约,

而不是一种语言。C表示符合C语言的编译和连接规约的任何语言。





第二层: JNI  层次编写

frameworks\base\services\forlinx_led_jni\LedService.cpp

struct led_control_device_t *sLedDevice = NULL;//硬件设备的公告属性和方法

//方法描述

gMethods[] = {

    { "_init","()Z",(void *)forlinx_init {

        jboolean forlinx_init(JNIEnv *env, jclass clazz)

        {

            led_module_t* module;

            hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module)

            {

                问:怎么获得模块信息的?

                答:hardware\libhardware\Hardware.c

                hw_get_module(const char *id, const struct hw_module_t **module)

                {

                    char prop[PATH_MAX];

                    char path[PATH_MAX];

                    for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++) 

                    {

                        property_get(variant_keys[i], prop, NULL)

                        {

                            问: variant_keys的数据是什么?

                            答: static const char *variant_keys[] = {

                                "ro.hardware",  

                                "ro.product.board",

                                "ro.board.platform",

                                "ro.arch"

                            };

                            问:ro.hardware代表的值是什么?

                            答: system\core\init\init.c

                            set_init_properties_action(int nargs, char **args)

                                property_set("ro.hardware", hardware)

                            get_hardware_name(char *hardware, unsigned int *revision)

                            {

                                //该函数在int main(int argc, char **argv)中被调用

                                fd = open("/proc/cpuinfo", O_RDONLY);

                                hw = strstr(data, "\nHardware");

                                while (*x && !isspace(*x)) {

                                    hardware[n++] = tolower(*x);

                                    x++;

                                    if (n == 31break;

                                }

                            }

                        }

                        snprintf(path, sizeof(path), "%s/%s.%s.so",HAL_LIBRARY_PATH1, id, prop);

                        {

                            #define HAL_LIBRARY_PATH1 "/system/lib/hw"

                        }

                    }

                    status = load(id, path, module); /* 调用load函数打开动态链接库 */

                }

                led_control_open(&module->common, &sLedDevice)

                {

                    led_control_open(const struct hw_module_t* module,struct led_control_device_t** device) {

                     return module->methods->open(module,LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);

                    }

                }

            }

        }

    }},

    { "_set_on",        "(I)Z", (void *)forlinx_setOn 

        {

             sLedDevice->set_on(sLedDevice, led);//sLedDevice:硬件设备的公告属性和方法

        }

    },

    { "_set_off",       "(I)Z", (void *)forlinx_setOff 

        {

            sLedDevice->set_off(sLedDevice, led);

        }

    },

}



int register_forlinx_server_LedService(JNIEnv* env) 

{

    charconst kClassName ="forlinx_led_server/server/LedService";

    /* look up the class */

    jclass clazz = env->FindClass(kClassName);

    /* 注册方法

    java类:    forlinx_led_server/server/LedService

    方法描述: gMethods

    
*/

    env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); //gMethods 方法描述数组

}





简单的Jni 例子都是映射模式,及对应的Jni 的c/c++ 实现需要,

被java的函数命名规则限制死,为了解决这类毛病,引入的JNI_OnLoad这类方法。

jint JNI_OnLoad(JavaVM* vm, void* reserved)

该方法在Jni so 被加载时调用。

当VM释放该组件时会呼叫JNI_OnUnload()函数

*/

jint JNI_OnLoad(JavaVM* vm, void* reserved)

{

    JNIEnv* env = NULL;

    jint result = -1;

    if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {

        LOGE("GetEnv failed!");

        return result;

    }

    register_forlinx_server_LedService(env);

    {

        charconst kClassName ="forlinx_led_server/server/LedService";

    }

    return JNI_VERSION_1_4;

}



第三层: Application Frameworks层增加硬件访问服务

1 接口文件指定

frameworks\base\Android.mk 指定接口文件

{

    LOCAL_SRC_FILES += \

    core/java/android/forlinx/ILedService.aidl \

}

2 接口定义 frameworks\base\core\java\android\forlinx\ILedService.aidl

package android.forlinx;

interface ILedService

{

    boolean setOn(int led);

    boolean setOff(int led);

}

3 实现类  

第一种方法:直接调用service方法的实现过程

import android.forlinx.ILedService;

public final class LedService  extends ILedService.Stub {

    //先与构造函数执行

    static

    {

        System.load("/system/lib/libforlinx_runtime.so"); //路径是怎么确定的?

    }   

    public LedService() {

         _init();

    }

    public boolean setOn(int led) 

    {

        return _set_on(led);

    }



    public boolean setOff(int led) {

        return _set_off(led);

    }



    private static native boolean _init();

    private static native boolean _set_on(int led);

    private static native boolean _set_off(int led);

}

第二种方法:经过Manager调用service  

为什么要这样做?

LedManager代理者模式,LedSystemServer单例模式

(1):添加服务 packages\apps\forlinxled\src\com\led\LedSystemServer.java

import forlinx_led_server.server.LedService;

public class LedSystemServer extends Service {

    @Override

    public IBinder onBind(Intent intent) { return null;}

    public void onStart(Intent intent, int startId) {

        if(ServiceManager.getService("led") == null//单例模式

        {

           LedService ls = new LedService();

           ServiceManager.addService("led", ls);

        }

    }

}

由Manager充当代理  代理模式

frameworks\base\core\java\android\forlinx\LedManager.java

public class LedManager

{

    private static final String TAG = "LedManager";

    private ILedService mLedService;



    public LedManager() {

        mLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));

    }



    public boolean LedOn(int n) {

        boolean result = false;

        if (mLedService == null//try 

        {

           mLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));

        }

        if(mLedService != null)

        {

          result = mLedService.setOn(n);

        }

        return result;

    }



    public boolean LedOff(int n) {

        boolean result = false;

        try {

              if (mLedService == null//try 

              {

                mLedService = ILedService.Stub.asInterface(

                ServiceManager.getService("led"));

              }

             if(mLedService != null)

             {

               Log.i(TAG, "The LedManager object will set off");

               result = mLedService.setOff(n);

             }



        } catch (RemoteException e) {

            Log.e(TAG, "RemoteException in LedManager.LedOff:", e);

        }

        return result;

    }

}







4 测试程序 第一种方法:直接调用service方法的实现过程

import android.widget.TextView;



public class LedClient extends Activity {

    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);



        // Call an API on the library.

        LedService ls = new LedService();

        ls.setOn(0);

        ls.setOn(1);

        ls.setOn(2);

        ls.setOn(3);

        TextView tv = new TextView(this);

        tv.setText("All Leds On");

        setContentView(tv);

    }

}

第二种方法:经过Manager调用service。HAL、JNI两层和第一种方法一样。



public class LedTest extends Activity implements OnClickListener {

    

    private LedManager mLedManager = null;

    private Button btnLED1On; 



    @Override

    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);

        setContentView(R.layout.main);

        

        // Start LedService in a seperated process.

        startService(new Intent("com.led.systemserver"));

        

        // Get LedManager.

        if (mLedManager == null

        {

           mLedManager = new LedManager();

        }

        btnLED1On = (Button)findViewById(R.id.btnLED1On);

        btnLED1On.setOnClickListener(this);

    }

    

    public void onClick(View v) {

        switch (v.getId()) {

            case R.id.btnLED1On:

                if (mLedManager != null)

                {

                    mLedManager.LedOn(0);

                }

                break;

            default:

                break;

        }

    }

}



    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多