网站建设 响应式,网站开发用什么后端框架,做网站建设的好处,wordpress 获取文章标签简介#xff1a;
HAL层又称硬件抽象层#xff0c;HAL层在Android体系中有着深远的意义#xff0c;因为Android究竟是完 全开源还是完全不开源的秘密就在这一层Google将硬件厂商的驱动程序放在这一层#xff0c;正是因为 这一层的代码没有开源#xff0c;所以Android被Lin…简介
HAL层又称硬件抽象层HAL层在Android体系中有着深远的意义因为Android究竟是完 全开源还是完全不开源的秘密就在这一层·Google将硬件厂商的驱动程序放在这一层正是因为 这一层的代码没有开源所以Android被Linux家族删除本章将详细介绍HAL层的基本知识 为本书后面的驱动开发和移植打下坚实的基础
1、认识 HAL 层
HAL层硬件抽象层是位于操作系统内核与硬件电路之间的接口层其目的在于将硬件抽象 化。它隐藏了特定平台的硬件接口细节为操作系统提供虚拟硬件平台使其具有硬件无关性这样就可以在多种平台上进行移植。从软、硬件测试的角度来看软、硬件的测试工作都可分别基于硬件抽象层来完成从此亻吏软、硬件测试工作的并行进行成为可能。HAL层的位置结构如冬6-1所示。 由图6-1可知HAL的目的是为了把Android Framework(Android框架与Linux Kernel(Linux 内核隔离。让Android不至过度依赖Linux Kemel从而让Android Framework的开发可在不 考虑驱动程序的前提下进行。HAL层主要包含GPS、Vibrator、Wi-Fi、Copybit、Audio、Camera、Lights、RiI、Overlay等模块。
1.1.1 HAL 层的发展
硬件抽象层大概分为一下 6种HAL:
上层软件虚拟驱动设置管理模块内部通信Server内部以太网内部通信Client用户接入口
定义硬件抽象层接口的代码具有一下5个特点
硬件抽象层具有与硬件的密切相关性硬件抽象层具有与操作系统无关性接口定义的功能应该包含硬件或者系统所需硬件支持的所有功能接口简单明了太多接口函数会增加软件模拟的复杂性具有可预测的接口设计有利于系统的软、硬件测试和集成。
在Android 源码中HAL 主要被保存在下面的目录中
libhardware_legacy 过去的目录采取链接库模块观念来架构libhardware: 新版的目录被调整为用HAL stub 观念来架构ril: 是Radio 接口层msm7k : 和QUAL 平台相关的信息
接下来将对目前HAL的现况做一个简单的分析。目前Android的HAL层仍旧散布在不同 的地方如分为camera、Wi-Fi等因此上述的目录并不包含所有的HAL程序代码。成熟前的 HAL架构如图62所示现在的HAL架构如图63所示。 从现在HAL层的结构可以看出当前的HAL stub模式是一种代理人(Proxy)的概念虽然 stub仍以 *.so 档的形式存在但是HAL己经将 *.so 档隐藏了。Stub向HAL提供了功能强大的操作 函数(Operations)而 runtime 则从 HAL获取特定模块(Stub)的函数然后再回调这些操作函 数。这种以 lndirect Function CAII 模式的架构让 HAL stub 变成了一种“包含”关系也就是说 在 HAL 中包含了许多 Stub代理人)。Runtime只要说明moduleID类型),就可以取得操作函数。 在当前的HAL模式中Android定义了HAL层结构框架这样通过接口访问硬件时就形成了统 一的调用方式。 1.1.2 过去和现在的区别 为了使读者明白过去结构和现在结构的差别接下来对HALlegacy和HAL做一个对比。
HAL_legacy这是过去HAL的模块采用共享库形式在编译时会调用到。由于采用functroncall形式调用因此可被多个进程使用但会被mapping到多个进程窄间中造成浪费同时需要考虑代码能否安全重入的问题(ThreadSafe)。HAL这是新式的HAL采用了HALmodule和HAL stub 结合形式。HALstub不是一个共 享库在编译时上层只拥有访问HALstub的函数指针并不需要HAL stub-在上层通过HAL module提供的统一接口获取并操作HAL stub所以文件只会被映射到一个进程而不会存 在重复映射和重入问题。 2.2 分析HAL 层源码 通过上节的学习了解了Android中为了给用户提供统一的硬件接口和硬件形态在Linux Kemel和用户空间之间提供了一个HAL层即硬件抽象层。这使得 Android 中的Framework只需要 关心HAL中的内容而不用关心具体的硬件实现。本节将简单分析HAL层的代码当然不是具体 驱动的代码而是HAL层中的各个接口的代码。
2.2.1 分析 HAL moudle
在 HAL moudle 中主要分为如下3个结构
struct hw_modulestruct hw_modulemethods_tstruct hw_device_t 上述 3 个结构的集成关系 如图 6-4 所示 上述3个抽象概念在文件hardware.c中进行了详细述。HAL模块的源代码保存在harware目 录中对于不同的 hardware 的HAL其对应的lib命名规则是id.variant.so比如gralloc.msm7k.so, 表示其id是grallocmsm7k是vanant。variant的取值范围是在该文件中的定义的vanant_keys对应 的值。
接下来分析 hardware.c 源码。
1函数hw_get_module()。此函数根据模块ID寻找硬件模块动态链接库的地址然后调用load去打开动态链接库并从中获取硬件模块结构体地址。执行后首先得到的是根据固定的符号 HAL_MODULE_INFO_SYM寻找到 hw_module_t 结构体然后在hw_moule_t中hw_module_methods_t 结构体成员函数提供的open结构打开相应的模块并进行初始化。因为用户在调用 open() 时通常都会传 入一个指向 hw_device_t 指针的指针。这样函数 open() 就将对模块的操作函数结构保存到hw_device_t 结构体中用户通过它可以和模块进行交互。
函数hw_get_module() 的具体实现代码如下
代码 /hardware/libhardware/hardware.c int hw_get_module_by_class(const char *class_id, const char *inst, const struct hw_module_t **module) { 1 通过配置变量 循环寻找一个模块 /* Loop through the configuration variants looking for a module */ for (i0 ; iHAL_VARIANT_KEYS_COUNT; i) { ······· 2数组variant_keys 在上述函数中需要用到数组variant_keys,因为HAL_VARIANT_KEYS_COUNT就是数组variant_keys的大小。定义此数组的代码如下 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 }; 然后通过此数组并使用如下代码获取操作权限 if (property_get(variant_keys[i], prop, NULL) 0) { continue; } if (hw_module_exists(path, sizeof(path), name, prop) 0) { goto found; } } 在此variant_keys[il对应有3个值分别是trout、msm7k和ARMV6, (3) 将路径和文件名保存到 path 接下来将通过如下代码将路径和文件保存在path 中 snprintf(path, path_len, %s/%s.%s.so, HAL_LIBRARY_PATH1, name, subname); 通过上述代码把 HAL_LIBRARY_PATH/id.***.so 保存到 path 中其中 **** 就是上面 variant_keys 中各个元素的值。 4 载入相应的库并把他们的 HMI 不保存到 module 中具体代码如下 /* 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, were doomed, and we should not try * to load a different variant. */ return load(class_id, path, module); 5打开相应的库并获得 hw_module_t 结构体具体代码如下 static int load(const char *id, const char *path, const struct hw_module_t **pHmi) { int status -EINVAL; void *handle NULL; struct hw_module_t *hmi NULL; #ifdef __ANDROID_VNDK__ const bool try_system false; #else const bool try_system true; #endif /* * load the symbols resolving undefined symbols before * dlopen returns. Since RTLD_GLOBAL is not ord in with * RTLD_NOW the external symbols will not be global */ if (try_system strncmp(path, HAL_LIBRARY_PATH1, strlen(HAL_LIBRARY_PATH1)) 0) { /* If the library is in system partition, no need to check * sphal namespace. Open it with dlopen. */ handle dlopen(path, RTLD_NOW); } else { #if defined(__ANDROID_RECOVERY__) handle dlopen(path, RTLD_NOW); #else handle android_load_sphal_library(path, RTLD_NOW); #endif } 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: couldnt 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, hmi, handle); } *pHmi hmi; return status; } 2.2.2 分析mokoid 工具
mokoid 工程中提供了一个LedTest示例程序此示例是我国台湾Jollen的培训教程。了解这个 工程源码对于理解Android层次结构、HAL编程方法都非常有意义。此工程文件码可以从网络 中获取在Linux中的下载命令如下 # svn checkout http://mokoid.googlecode.com/svn/trunk/mokoid-read-only 下载 mokoid 工程之后目录结构如图6-5所示
需要通过 JNI 来实现 Android 的HAL, JNI 是Java 程序可以调用C/C 写的动态链接库所以HALkeyi shiyong C/C语言编写这样效率更高。在Android 下有以下两种访问HAL 的方式
Android 的app 直接通过 service 调用.so 格式的JNI 此方法比较简单高效但是不正规。经过 Manager 调用 Service : 此方法实现起来比较复杂但是更符合目前的Android 框架。在此方法中在进程 LegManager 和 LedService (Java) 中需要通过进程通信的方式实现通信。
在 mokoid 工程中分别实现上述两种方法下面将详细介绍这两种方法实现原理:
1.直接调用 Service 方法的实现代码
1HAL 层的实现代码
文件 hardware/modules/led/led.c 的实现代码如下 #define LOG_TAG MokoidLedStub #include hardware/hardware.h #include fcntl.h #include errno.h #include cutils/log.h #include cutils/atomic.h #include mokoid/led.h /*****************************************************************************/ int led_device_close(struct hw_device_t* device) { struct led_control_device_t* ctx (struct led_control_device_t*)device; if (ctx) { free(ctx); } return 0; } int led_on(struct led_control_device_t *dev, int32_t led) { LOGI(LED Stub: set %d on., led); return 0; } int led_off(struct led_control_device_t *dev, int32_t led) { LOGI(LED Stub: set %d off., led); return 0; } 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, 0, sizeof(*dev)); dev-common.tag HARDWARE_DEVICE_TAG; dev-common.version 0; dev-common.module module; dev-common.close led_device_close; dev-set_on led_on; // 实例化支持的操作 dev-set_off led_off; *device dev-common; // 将实例化的 led_control_device_t 地址返回给 Jni 层 success: return 0; } static struct hw_module_methods_t led_module_methods { open: led_device_open }; 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 Mokoid Open Source Project, methods: led_module_methods, } /* supporting APIs go here */ }; 2 JNI 层的实例代码
文件 frameworks/base/service/jni/com_mokoid_server_LedService.cpp 的实现代码如下 #define LOG_TAG MokoidPlatform #include utils/Log.h #include stdlib.h #include string.h #include unistd.h #include assert.h #include jni.h #include mokoid/led.h // ---------------------------------------------------------------------------- struct led_control_device_t *sLedDevice NULL; static jboolean mokoid_setOn(JNIEnv* env, jobject thiz, jint led) { LOGI(LedService JNI: mokoid_setOn() is invoked.); if (sLedDevice NULL) { LOGI(LedService JNI: sLedDevice was not fetched correctly.); return -1; } else { return sLedDevice-set_on(sLedDevice, led); // 调用 HAL 层的注册方法 } } static jboolean mokoid_setOff(JNIEnv* env, jobject thiz, jint led) { LOGI(LedService JNI: mokoid_setOff() is invoked.); if (sLedDevice NULL) { LOGI(LedService JNI: sLedDevice was not fetched correctly.); return -1; } else { return sLedDevice-set_on(sLedDevice, led); // 调用 HAL 层的注册方法 } } /** helper APIs */ // JNI 通过 LED_HARDSOFTWARE_MODULE_ID 找到对应的stub static inline int 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); } static jboolean mokoid_init(JNIEnv *env, jclass clazz) { led_module_t* module; if (hw_get_module(LED_HARDWARE_MODULE_ID, (const hw_module_t**)module) 0) { LOGI(LedService JNI: LED Stub found.); if (led_control_open(module-common, sLedDevice) 0) { LOGI(LedService JNI: Got Stub operations.); return 0; } } LOGE(LedService JNI: Get Stub operations failed.); return -1; } // ---------------------------------------------------------------------------- /* * Array of methods. * * Each entry has three fields: the name of the method, the method * signature, and a pointer to the native implementation. * JNI NativeMethod 是java 层的注册方法 */ static const JNINativeMethod gMethods[] { {_init, ()Z, // Framwork 层调用 _init 时触发 (void*)mokoid_init}, { _set_on, (I)Z, (void*)mokoid_setOn }, { _set_off, (I)Z, (void*)mokoid_setOff }, }; static int registerMethods(JNIEnv* env) { static const char* const kClassName com/mokoid/server/LedService; jclass clazz; /* look up the class */ clazz env-FindClass(kClassName); if (clazz NULL) { LOGE(Cant find class %s\n, kClassName); return -1; } /* register all the methods */ if (env-RegisterNatives(clazz, gMethods, sizeof(gMethods) / sizeof(gMethods[0])) ! JNI_OK) { LOGE(Failed registering methods for %s\n, kClassName); return -1; } /* fill out the rest of the ID cache */ return 0; } // ---------------------------------------------------------------------------- /* * This is called by the VM when the shared library is first loaded. */ 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(ERROR: GetEnv failed\n); goto bail; } assert(env ! NULL); if (registerMethods(env) ! 0) { LOGE(ERROR: PlatformLibrary native registration failed\n); goto bail; } /* success -- return valid version number */ result JNI_VERSION_1_4; bail: return result; } 3 Service 的实现代码
这里的service 属于 Framwork 层文件 framworks/base/service/java/com/mokoid/server/LedService.java 的实现代码 package com.mokoid.server; import android.util.Config; import android.util.Log; import android.content.Context; import android.os.Binder; import android.os.Bundle; import android.os.RemoteException; import android.os.IBinder; import mokoid.hardware.ILedService; public final class LedService extends ILedService.Stub { static { System.load(/system/lib/libmokoid_runtime.so); } public LedService() { Log.i(LedService, Go to get LED Stub...); _init(); } /* * Mokoid LED native methods. */ public boolean setOn(int led) { Log.i(MokoidPlatform, LED On); return _set_on(led); } public boolean setOff(int led) { Log.i(MokoidPlatform, LED Off); 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); } 4 App 测试程序的实现代码 这里的测试程序属于 APP 层文件 apps/LedClient/src/com/mokoid/LedClient/LedClient.java 的实现代码如下 package com.mokoid.LedClient; import com.mokoid.server.LedService; import android.app.Activity; import android.os.Bundle; 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(1); TextView tv new TextView(this); tv.setText(LED 0 is on.); setContentView(tv); } } 2、通过 manager 调用 Service 的实现代码
1 Manager 的实现代码
APP 通过 此 Manager 和 Service 实现通信功能文件 framwork/base/core/java/mokoid/hardware/Ledmanager.java package mokoid.hardware; import android.content.Context; import android.os.Binder; import android.os.Bundle; import android.os.Parcelable; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteException; import android.os.Handler; import android.os.Message; import android.os.ServiceManager; import android.util.Log; import mokoid.hardware.ILedService; /** * Class that lets you access the Mokoid LedService. */ public class LedManager { private static final String TAG LedManager; private ILedService mLedService; public LedManager() { mLedService ILedService.Stub.asInterface( ServiceManager.getService(led)); if (mLedService ! null) { Log.i(TAG, The LedManager object is ready.); } } public boolean LedOn(int n) { boolean result false; try { result mLedService.setOn(n); } catch (RemoteException e) { Log.e(TAG, RemoteException in LedManager.LedOn:, e); } return result; } public boolean LedOff(int n) { boolean result false; try { result mLedService.setOff(n); } catch (RemoteException e) { Log.e(TAG, RemoteException in LedManager.LedOff:, e); } return result; } } 因为 LedService 和 Ledmanager 分别不属于不同的进程所以在此需要考虑不同进程间的通信问题此时在 manager 中可以增加一个aidl 文件来描述通信接口文件
framworks/base/core/java/mokoid/hardware/ILedService.aidl 的代码实现如下 package mokoid.hardware; interface ILedService { boolean setOn(int led); boolean setOff(int led); } 2 SystemService 的实现代码
此处的 SystemServer 属于 App 层文件 apps /LedTest/src/com/mokoid/LedTest/Ledsystem/Server.java 的代码如下 package com.mokoid.LedTest; import com.mokoid.server.LedService; import android.os.IBinder; import android.os.ServiceManager; import android.util.Log; import android.app.Service; import android.content.Context; import android.content.Intent; public class LedSystemServer extends Service { Override public IBinder onBind(Intent intent) { return null; } public void onStart(Intent intent, int startId) { Log.i(LedSystemServer, Start LedService...); /* Please also see SystemServer.java for your interests. */ LedService ls new LedService(); try { ServiceManager.addService(led, ls); } catch (RuntimeException e) { Log.e(LedSystemServer, Start LedService failed.); } } } 3.App 测试程序
这里的app测试程序属于APP 层文件 mokoid-read-only/apps/LedTest/src/com/mokoid/LedTest/LedTest.java 的实现代码如下 package com.mokoid.LedTest; import mokoid.hardware.LedManager; import com.mokoid.server.LedService; import android.app.Activity; import android.os.Bundle; import android.util.Log; import android.widget.TextView; import android.widget.Button; import android.content.Intent; import android.view.View; public class LedTest extends Activity implements View.OnClickListener { private LedManager mLedManager null; Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Start LedService in a seperated process. startService(new Intent(com.mokoid.systemserver)); // Just for testing. !! PLEASE DONt DO THIS !! //LedService ls new LedService(); Button btn new Button(this); btn.setText(Click to turn LED 1 On); btn.setOnClickListener(this); setContentView(btn); } public void onClick(View v) { // Get LedManager. if (mLedManager null) { Log.i(LedTest, Creat a new LedManager object.); mLedManager new LedManager(); } if (mLedManager ! null) { Log.i(LedTest, Got LedManager object.); } /** Call methods in LedService via proxy object * which is provided by LedManager. */ mLedManager.LedOn(1); TextView tv new TextView(this); tv.setText(LED 1 is On.); setContentView(tv); } } 4、使用HAL 的方法 总结
1Native code 通过hw_get_module 调用获取 HAL stub.
hw_get_module (LED_HARDWARE_MODULE_ID,(const hw_module_t** )module)
(2) 通过继承 hw_module_methods_t 的 callback 拉打开设备。
module-methods-open(module,LED_HARDWARE_MODULE_ID,(struct hw_device_t**)device);
(3) 通过继承 hw_device_t 的callback 回访 来控制设备
sLedDevice - set_on(sLedDevice,led);
sLedDevice- set_off(sLedDevice,led); 4.1. 编写 HAL stub 的方法
编写HAL stub 的基本流程入下图所示。
1自定义 HAL 结构体编写 头文件 led.h 和 hardware/hardware.h 主要代码如下 struct ledmodulet { struct hw_module_t common; } struct led_control_device_t { struct hw_device_t common; int fd ; // 文件描述符 的 LED 装置 int (*set_on) (struct led_control_device_t *dev, int32_t led); // 支持控制的 api int (*set_off) (struct led_control_device_t *dev,int32_t led); } (2) 编写 文件 led.c 实现 HAL stub 注册功能
3设置 led_module_methods 继承于 hw_module_methods_t,并实现对 open() 方法的回访 struct hw_module_methods_t led_module_methods { open : led_device_open }; (4) 使用 HAL_MODULE_INFO_SYM 实例led_module_t, 注意 这个名称不可修改 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 Mokoid Open Source Project, methods led_module_methods, } // 支持 api }; (5) open() 是一个必须实现的回调 API 用于负责 申请 结构体空间并填充信息还可以注册具体操作API 接口 并打开 Linux 驱动。但是系因为存在多重继承关系所以只需要对结构体hw_device_t 对象申请空间即可。 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, 0, sizeof(*dev)); dev-common.tag HARDWARE_DEVICE_TAG; dev-common.version 0; dev-common.module module; dev-common.close led_device_close; dev-set_on led_on; dev-set_off led_off; *device dev-common; // 初始化硬件接口 dev-fd open(LED_DEVICE,o_RDONLY); if (dev-fd 0 ) { return -1; } led_off(dev,LED_C608); led_off(dev,LED_C609); success: return 0; } (6) 填充具体 API 操作具体代码如下 int led_on (struct led_control_device_t *dev,int32_t led) { int fd; LOGI(LED Stub: set %d on.,led); fd dev-fd; switch(led) { case LED_C608: ioctl(fd,1,led); break; case LED_C609: ioctl(fd,1,led) break; default: return -1; } return 0; } int led_off (struct led_control_device_t *dev,int32_t led) { int fd; LOGILED Stub : set %d off.,led; fd dev- fd; switch(led) { case LED_C608: ioctl(fd,2,led); break; case LED_C609: ioctl(fd,2,led); break; default: return -1; } return 0; } 文章摘自
《Android 底层接口和驱动开发技术详解》
相关资料下载跳转