Android HAL技术详解

本人喜欢用代码+伪代码的方式写笔记。文中的花括号可能是方便记录而已。

如:

hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module)
{
    问:怎么获得模块信息的?
    答:hardware\libhardware\Hardware.c

    ...........

}

原创分析, 转载请注明出处:http://www.cnblogs.com/langlang/

作者email: dayhappyhappy@163.com

第一部分: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;
        }
    }
}

 

转载于:https://www.cnblogs.com/langlang/archive/2012/04/17/2454217.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值