主题 : Android HAL技术详解 复制链接 | 浏览器收藏 | 打印
级别: 新手上路
UID: 36252
精华: 0
发帖: 7
金钱: 35 两
威望: 7 点
贡献值: 0 点
综合积分: 14 分
注册时间: 2011-01-13
最后登录: 2012-04-28
楼主  发表于: 2012-04-22 15:46

 Android HAL技术详解

本人喜欢用代码+伪代码的方式写笔记。文中的花括号可能是方便记录而已。
如:
hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module)
{
    问:怎么获得模块信息的?
    答:hardware\libhardware\Hardware.c
    ...........
}
作者email: dayhappyhappy@163.com


第一部分:HAL层
hardware\led\include\Led.h
定义数据结构
复制代码
  1. struct led_module_t {
  2.    struct hw_module_t common;
  3. };
  4. struct led_control_device_t {  
  5.    struct hw_device_t common;  /*表示硬件设备*/
  6.    /* 属性 */
  7.    int fd;
  8.    /* 提供出来的方法 */
  9.    int (*set_on)(struct led_control_device_t *dev, int32_t led);
  10.    int (*set_off)(struct led_control_device_t *dev, int32_t led);
  11. };
  12. nstruct led_control_context_t {
  13.     struct led_control_device_t device;
  14. };


hardware\led\led\Led.cpp 分析
复制代码
  1. static int led_device_open(const struct hw_module_t* module, const char* name,
  2.         struct hw_device_t** device)
  3. {
  4.     struct led_control_device_t *dev;
  5.     /* 分配设备 */
  6.     dev = (struct led_control_device_t *)malloc(sizeof(*dev));
  7.     memset(dev, 0, sizeof(*dev));
  8.     dev->common.tag =  HARDWARE_DEVICE_TAG;
  9.     dev->common.version = 0;
  10.     dev->common.module = (struct hw_module_t*)module;  /*设置是属于哪个模块 */
  11.     dev->common.close = led_device_close;
  12.     
  13.     dev->set_on = led_on;
  14.         /*自定义方法*/
  15.         int led_on(struct led_control_device_t *dev, int32_t led)
  16.             ioctl(g_fd, 0, led); //led on
  17.     dev->set_off = led_off;    /*自定义方法*/
  18.     *device = &dev->common;
  19.     /*
  20.     /dev/leds0 内核驱动的device_create创建的
  21.     假如打开设备时候发生:Hello Stub: failed to open /dev/leds0 -- Permission denied.
  22.     进入到system/core/rootdir目录,里面有一个名为ueventd.rc文件,往里面添加一行:
  23.      /dev/hello 0666 root leds0
  24.     */
  25.      g_fd = open("/dev/leds0", 0);
  26.     return 0;
  27. }
  28. /*模块方法表*/  
  29. static struct hw_module_methods_t led_module_methods = {
  30.     open: led_device_open
  31. };
  32. /*  
  33.     模块信息
  34.     实例变量名必须为HAL_MODULE_INFO_SYM,
  35.     tag也必须为HARDWARE_MODULE_TAG,这是Android硬件抽象层规范规定的。
  36. */
  37. extern "C" ① const struct led_module_t HAL_MODULE_INFO_SYM = {
  38.     common: {
  39.         tag: HARDWARE_MODULE_TAG,  
  40.         version_major: 1,
  41.         version_minor: 0,
  42.         id: LED_HARDWARE_MODULE_ID,
  43.         name: "Sample LED Stub",
  44.         author: "The Forlinx Open Source Project",
  45.         methods: &led_module_methods,  /*设置方法  */
  46.     }
  47.     /* supporting APIs go here */
  48. };

① extern "C" :C++编写的代码片段可能被使用在其它语言编写的代码中。不同语言编写的代码互相调用是困难的。
为了使它们遵守统一规则,可以使用extern指定一个编译和连接规约。extern "C"指令中的C,表示的一种编译和连接规约,
而不是一种语言。C表示符合C语言的编译和连接规约的任何语言。


第二层: JNI  层次编写
frameworks\base\services\forlinx_led_jni\LedService.cpp
复制代码
  1. struct led_control_device_t *sLedDevice = NULL;//硬件设备的公告属性和方法
  2. //方法描述
  3. gMethods[] = {
  4.     { "_init",          "()Z",    (void *)forlinx_init {
  5.         jboolean forlinx_init(JNIEnv *env, jclass clazz)
  6.             led_module_t* module;
  7.             hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)&module)
  8.                 问:怎么获得模块信息的?
  9.                 答:hardware\libhardware\Hardware.c
  10.                 hw_get_module(const char *id, const struct hw_module_t **module)
  11.                     char prop[PATH_MAX];
  12.                     char path[PATH_MAX];
  13.                     for (i=0 ; i<HAL_VARIANT_KEYS_COUNT+1 ; i++)
  14.                         property_get(variant_keys[i], prop, NULL)
  15.                             问: variant_keys的数据是什么?
  16.                             答: static const char *variant_keys[] = {
  17.                                 "ro.hardware",  
  18.                                 "ro.product.board",
  19.                                 "ro.board.platform",
  20.                                 "ro.arch"
  21.                             };
  22.                             问:ro.hardware代表的值是什么?
  23.                             答: system\core\init\init.c
  24.                             set_init_properties_action(int nargs, char **args)
  25.                                 property_set("ro.hardware", hardware)
  26.                             get_hardware_name(char *hardware, unsigned int *revision)
  27.                                 //该函数在int main(int argc, char **argv)中被调用
  28.                                 fd = open("/proc/cpuinfo", O_RDONLY);
  29.                                 hw = strstr(data, "\nHardware");
  30.                                 while (*x && !isspace(*x)) {
  31.                                     hardware[n++] = tolower(*x);
  32.                                     x++;
  33.                                     if (n == 31) break;
  34.                                 }
  35.                             }
  36.                         }
  37.                         snprintf(path, sizeof(path), "%s/%s.%s.so",HAL_LIBRARY_PATH1, id, prop);
  38.                         {
  39.                             #define HAL_LIBRARY_PATH1 "/system/lib/hw"
  40.                         }
  41.                     }
  42.                     status = load(id, path, module); /* 调用load函数打开动态链接库 */
  43.                 }
  44.                 led_control_open(&module->common, &sLedDevice)
  45.                 {
  46.                     led_control_open(const struct hw_module_t* module,struct led_control_device_t** device) {
  47.                      return module->methods->open(module,LED_HARDWARE_MODULE_ID, (struct hw_device_t**)device);
  48.                     }
  49.                 }
  50.             }
  51.         }
  52.     }},
  53.     { "_set_on",        "(I)Z", (void *)forlinx_setOn
  54.         {
  55.              sLedDevice->set_on(sLedDevice, led);//sLedDevice:硬件设备的公告属性和方法
  56.         }
  57.     },
  58.     { "_set_off",       "(I)Z", (void *)forlinx_setOff
  59.         {
  60.             sLedDevice->set_off(sLedDevice, led);
  61.         }
  62.     },
  63. }
  64. int register_forlinx_server_LedService(JNIEnv* env)
  65. {
  66.     char* const kClassName ="forlinx_led_server/server/LedService";
  67.     /* look up the class */
  68.     jclass clazz = env->FindClass(kClassName);
  69.     /* 注册方法
  70.     java类:    forlinx_led_server/server/LedService
  71.     方法描述: gMethods
  72.     */
  73.     env->RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])); //gMethods 方法描述数组
  74. }
  75. 简单的Jni 例子都是映射模式,及对应的Jni 的c/c++ 实现需要,
  76. 被java的函数命名规则限制死,为了解决这类毛病,引入的JNI_OnLoad这类方法。
  77. jint JNI_OnLoad(JavaVM* vm, void* reserved)
  78. 该方法在Jni so 被加载时调用。
  79. 当VM释放该组件时会呼叫JNI_OnUnload()函数
  80. */
  81. jint JNI_OnLoad(JavaVM* vm, void* reserved)
  82. {
  83.     JNIEnv* env = NULL;
  84.     jint result = -1;
  85.     if (vm->GetEnv((void**) &env, JNI_VERSION_1_4) != JNI_OK) {
  86.         LOGE("GetEnv failed!");
  87.         return result;
  88.     }
  89.     register_forlinx_server_LedService(env);
  90.     {
  91.         char* const kClassName ="forlinx_led_server/server/LedService";
  92.     }
  93.     return JNI_VERSION_1_4;
  94. }

第三层: 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方法的实现过程
frameworks\base\services\forlinx_led_server\server\LedService.java
复制代码
  1. import android.forlinx.ILedService;
  2. public final class LedService  extends ILedService.Stub {
  3.     //先与构造函数执行
  4.     static
  5.     {
  6.         System.load("/system/lib/libforlinx_runtime.so"); //路径是怎么确定的?
  7.     }  
  8.     public LedService() {
  9.          _init();
  10.     }
  11.     public boolean setOn(int led)
  12.     {
  13.         return _set_on(led);
  14.     }
  15.     public boolean setOff(int led) {
  16.         return _set_off(led);
  17.     }
  18.     private static native boolean _init();
  19.     private static native boolean _set_on(int led);
  20.     private static native boolean _set_off(int led);
  21. }

第二种方法:经过Manager调用service  
为什么要这样做?
LedManager代理者模式,LedSystemServer单例模式
(1):添加服务 packages\apps\forlinxled\src\com\led\LedSystemServer.java
复制代码
  1. import forlinx_led_server.server.LedService;
  2. public class LedSystemServer extends Service {
  3.     @Override
  4.     public IBinder onBind(Intent intent) { return null;}
  5.     public void onStart(Intent intent, int startId) {
  6.         if(ServiceManager.getService("led") == null) //单例模式
  7.         {
  8.            LedService ls = new LedService();
  9.            ServiceManager.addService("led", ls);
  10.         }
  11.     }
  12. }

由Manager充当代理  代理模式
frameworks\base\core\java\android\forlinx\LedManager.java
复制代码
  1. public class LedManager
  2. {
  3.     private static final String TAG = "LedManager";
  4.     private ILedService mLedService;
  5.     public LedManager() {
  6.         mLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
  7.     }
  8.     public boolean LedOn(int n) {
  9.         boolean result = false;
  10.         if (mLedService == null) //try
  11.         {
  12.            mLedService = ILedService.Stub.asInterface(ServiceManager.getService("led"));
  13.         }
  14.         if(mLedService != null)
  15.         {
  16.           result = mLedService.setOn(n);
  17.         }
  18.         return result;
  19.     }
  20.     public boolean LedOff(int n) {
  21.         boolean result = false;
  22.         try {
  23.               if (mLedService == null) //try
  24.               {
  25.                 mLedService = ILedService.Stub.asInterface(
  26.                 ServiceManager.getService("led"));
  27.               }
  28.              if(mLedService != null)
  29.              {
  30.                Log.i(TAG, "The LedManager object will set off");
  31.                result = mLedService.setOff(n);
  32.              }
  33.         } catch (RemoteException e) {
  34.             Log.e(TAG, "RemoteException in LedManager.LedOff:", e);
  35.         }
  36.         return result;
  37.     }
  38. }



4 测试程序 第一种方法:直接调用service方法的实现过程
复制代码
  1. import android.widget.TextView;
  2. public class LedClient extends Activity {
  3.     @Override
  4.     public void onCreate(Bundle savedInstanceState) {
  5.         super.onCreate(savedInstanceState);
  6.         // Call an API on the library.
  7.         LedService ls = new LedService();
  8.         ls.setOn(0);
  9.         ls.setOn(1);
  10.         ls.setOn(2);
  11.         ls.setOn(3);
  12.         TextView tv = new TextView(this);
  13.         tv.setText("All Leds On");
  14.         setContentView(tv);
  15.     }
  16. }

第二种方法:经过Manager调用service。HAL、JNI两层和第一种方法一样。
复制代码
  1. public class LedTest extends Activity implements OnClickListener {
  2.     
  3.     private LedManager mLedManager = null;
  4.     private Button btnLED1On;
  5.     @Override
  6.     public void onCreate(Bundle savedInstanceState) {
  7.         super.onCreate(savedInstanceState);
  8.         setContentView(R.layout.main);
  9.         
  10.         // Start LedService in a seperated process.
  11.         startService(new Intent("com.led.systemserver"));
  12.         
  13.         // Get LedManager.
  14.         if (mLedManager == null)
  15.         {
  16.            mLedManager = new LedManager();
  17.         }
  18.         btnLED1On = (Button)findViewById(R.id.btnLED1On);
  19.         btnLED1On.setOnClickListener(this);
  20.     }
  21.     
  22.     public void onClick(View v) {
  23.         switch (v.getId()) {
  24.             case R.id.btnLED1On:
  25.                 if (mLedManager != null)
  26.                 {
  27.                     mLedManager.LedOn(0);
  28.                 }
  29.                 break;
  30.             default:
  31.                 break;
  32.         }
  33.     }
  34. }
[ 此帖被alan加油在2012-04-22 15:55重新编辑 ]
菜鸟在路上
级别: 圣骑士
UID: 42749
精华: 6
发帖: 241
金钱: 1530 两
威望: 306 点
贡献值: 6 点
综合积分: 602 分
注册时间: 2011-04-11
最后登录: 2016-07-19
1楼  发表于: 2012-04-23 08:23
好文章