Android HAL硬件抽象层与硬件系统架构
背景
近几年是互联网高速发展的几年,孕育出了如谷歌、阿里巴巴等许多超级互联网公司,随着互联网的发展已经触到了天花板,一个比互联网更大的市场即将打开,那就是物联网(Internet of Things)。IOT就是将现实世界中的物体连到互联网上,使得物与物、人与物可以很方便的互相沟通,将是下一个规模更大网络发展机遇的风口,是一个高科技公司抢占技术高地和风口,谷歌近日发布了第一代物联网平台操作系统Android Things。华为也推出了IOT操作系统LiteOS。
说到IOT,我们最多的是理解成智能硬件,万物互联;确实,IOT系统的每个节点都是不同的智能硬件,都是不同的网络智能终端设备。咱们丰巢快递智能柜也在某种程度上说也属于IOT设备。所以开发基于Android系统的丰巢智能柜,高铁寄存柜;我们有必要去搞懂Android的硬件系统和HAL层,正好我以前有过Android系统开发和HAL驱动开发的经验,和大家分享讨论下硬件相关知识。
整体架构
如图,Android系统的整个架构由五层结构组成:
- 应用层(Applications):这一层主要用于手机应用的安装,如系统自带联系人、短信等程序,或是第三方应用程序;
- 应用框架层(Application framework):这一层主要提供构建应用程序时可能用到的各种API,Android自带的一些核心应用就是使用这些API完成的,开发者也可通过使用API来构建自己的应用程序;
- 系统运行库层(Libraries And Runtimes):这一层通过一些C/C++库(so库)来为Android系统提供了主要的特性支持。如SQLite库提供了数据库支持,OpenGL ES库提供了3D绘图支持,Webkit库提供了浏览器内核支持等;
- 硬件抽象层(hardware abstraction layer):安卓驱动硬件的方式与Linux不尽相同。传统Linux的驱动完全存活于内核空间。硬件抽象层(HAL, Hardware Abstraction Layer),把一部分驱动功能放到HAL层中。安卓为什么费尽麻烦增加一个HAL呢?为了保护源代码。Linux内核采用了GPL协议,所以硬件生产商想要支持Linux系统,必须遵照GPL协议公开硬件驱动的源代码。但这些源代码中包含有许多硬件的设计信息,牵涉到硬件生产商的核心利益。而增加了HAL层之后,硬件厂商就不需要开放所有的驱动代码了。
- Linux内核层(Linux Kernel):Android系统基于Linux2.6内核,这一层为Android设备各种硬件提供了底层驱动,如显示驱动、音频驱动、照相机驱动、蓝牙驱动、Wi-Fi驱动、电源管理等;
Android HAL层不是Android一直都存在的,是从android4.0.3开始才加入的。Android的HAL是为了保护一些硬件提供商的知识产权而提出的,是为了避开linux的GPL束缚。思路是把控制硬件的动作都放到了Android HAL中,而linux driver仅仅完成一些简单的数据交互作用,甚至把硬件寄存器空间直接映射到user space。而Android是基于Aparch的license,因此硬件厂商可以只提供二进制代码,所以说Android只是一个开放的平台,并不是一个开源的平台。也许也正是因为Android不遵从GPL,所以Greg Kroah-Hartman才在2.6.33内核将Andorid驱动从linux中删除。GPL和硬件厂商目前还是有着无法弥合的裂痕。Android想要把这个问题处理好也是不容易的。
总结下来,Android HAL存在的原因主要有:
1. 并不是所有的硬件设备都有标准的linux kernel的接口;
2. KERNEL DRIVER涉及到GPL的版权。某些设备制造商并不原因公开硬件驱动,所以才去用HAL方 式绕过GPL;
3. 针对某些硬件,Android有一些特殊的需求
硬件系统架构介绍
目前存在两种HAL架构,位于libhardware_legacy目录下的“旧硬件架构架构”和位于libhardware目录下的“新HAL架构”。两种框架如下图所示。
老的硬件架构libhardware_legacy 是将 *.so 文件当作shared library来使用,在runtime(JNI 部份)以 direct function call 使用 HAL module。通过直接函数调用的方式,来操作驱动程序。当然,应用程序也可以不需要通过 JNI 的方式进行,直接加载 .so (dlopen)的做法调用.so 里的符号(symbol)也是一种方式。总而言之是没有经过封装,上层可以直接操作硬件。
现在的 libhardware HAL架构,就有stub的味道了。HAL stub 是一种代理人(proxy)的概念,stub 虽然仍是以 *.so库的形式存在,但HAL已经将 *.so 库隐藏起来了。Stub 向 HAL提供操作函数(operations),而 runtime 则是向 HAL 取得特定模块(stub)的 operations,再 callback 这些操作函数。这种以 indirect function call 的架构,让HAL stub 变成是一种包含关系,即 HAL 里包含了许许多多的 stub(代理人)。Runtime 只要说明类型,即 module ID,就可以取得操作函数。对于目前的HAL,可以认为Android定义了HAL层结构框架,通过几个接口访问硬件从而统一了调用方式。
硬件架构源码分析
下面我们从普通的振动器硬件的控制vibrate使用开始,从振动器服务的获取getSystemService方法,然后到硬件服务的调用,然后通过HAL硬件抽象层打开硬件驱动节点文件读写等操作,然后到Linux内核态驱动程序,以及处理器芯片引脚的控制与芯片时序驱动,一步一步讲解Android的新的硬件系统架构HAL架构是怎么进行硬件设备调度和控制的…
[外链图片转存失败]
APP层
Android应用层对振动器的调用形式一般是,通过获取到Vibrator实例后,通过实例方法vibrate来控制震动器的振动操作
Vibrator mVibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);
mVibrator.vibrate(500);
通过源码跟踪,通常调getSystemService调的是ContextImpl里面的getSystemService方法
framework层
位置:frameworks\base\core\java\android\app\ContextImpl.java
@Override
public Object getSystemService(String name) {ServiceFetcher fetcher = SYSTEM_SERVICE_MAP.get(name);return fetcher == null ? null : fetcher.getService(this);
}
可以看出是从SYSTEM_SERVICE_MAP集合里面通过那么作为key进行取出ServiceFetcher,然后getService获取到服务的实例。那SYSTEM_SERVICE_MAP集合里面存的服务实例是从哪里来呢?
private static final HashMap<String, ServiceFetcher> SYSTEM_SERVICE_MAP =new HashMap<String, ServiceFetcher>();private static void registerService(String serviceName, ServiceFetcher fetcher) {if (!(fetcher instanceof StaticServiceFetcher)) {fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;}SYSTEM_SERVICE_MAP.put(serviceName, fetcher);
}private static void registerService(String serviceName, ServiceFetcher fetcher) {if (!(fetcher instanceof StaticServiceFetcher)) {fetcher.mContextCacheIndex = sNextPerContextServiceCacheIndex++;}SYSTEM_SERVICE_MAP.put(serviceName, fetcher);}static {...registerService(VIBRATOR_SERVICE, new ServiceFetcher() {public Object createService(ContextImpl ctx) {return new SystemVibrator(ctx);}});...
}
实际上SYSTEM_SERVICE_MAP里面添加的服务Fetcher是通过类静态块进行registerService注册进去的。接下来我们看看SystemVibrator类的实现
位置:frameworks\base\core\java\android\os\SystemVibrator.java
public class SystemVibrator extends Vibrator {private static final String TAG = "Vibrator";private final IVibratorService mService;private final Binder mToken = new Binder();public SystemVibrator() {mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));}public SystemVibrator(Context context) {super(context);mService = IVibratorService.Stub.asInterface(ServiceManager.getService("vibrator"));}@Overridepublic boolean hasVibrator() {...return mService.hasVibrator();}/*** @hide*/@Overridepublic void vibrate(int uid, String opPkg, long milliseconds, AudioAttributes attributes) {...mService.vibrate(uid, opPkg, milliseconds, usageForAttributes(attributes), mToken);}...@Overridepublic void cancel() {...mService.cancelVibrate(mToken);}
}
SystemVibrator类相当于一个代理类,主要是通过Binder通信拿到IVibratorService,然后去远程调用对应的方法
,我们看到远程的Service IBinder是怎么获取过来的,看看ServiceManager.getService(“vibrator”)查找ServiceManager的getService方法的具体实现
位置:frameworks\base\core\java\android\os\ServiceManager.java
public final class ServiceManager {private static final String TAG = "ServiceManager";private static IServiceManager sServiceManager;private static HashMap<String, IBinder> sCache = new HashMap<String, IBinder>();private static IServiceManager getIServiceManager() {if (sServiceManager != null) {return sServiceManager;}// Find the service managersServiceManager = ServiceManagerNative.asInterface(BinderInternal.getContextObject());return sServiceManager;}....public static IBinder getService(String name) {try {IBinder service = sCache.get(name);if (service != null) {return service;} else {return getIServiceManager().getService(name);}} catch (RemoteException e) {Log.e(TAG, "error in getService", e);}return null;}public static void addService(String name, IBinder service) {try {getIServiceManager().addService(name, service, false);} catch (RemoteException e) {Log.e(TAG, "error in addService", e);}}....}
ServiceManager.getService(“vibrator”)获取到的IBinder是从sCache HashMap里面获取到的,我们查查是怎么添加进去的。
位置:frameworks\base\services\java\com\android\server\SystemServer.java
public static void main(String[] args) {new SystemServer().run();
}//run
private void run() {...//开始启动服务startBootstrapServices();//开启核心服务startCoreServices();//开启另外一些服务startOtherServices();...
}
//startOtherServices
private void startOtherServices() {...Slog.i(TAG, "Vibrator Service");vibrator = new VibratorService(context);ServiceManager.addService("vibrator", vibrator);
}
系统在初始化时候,SystemServer.main()方法,然后调用run调用了startOtherServices()这时候可以看出其实是在SystemServer注册了VibratorService服务,然后加入了ServiceManager里面去管理.想知道Android系统启动流程,可以看看我的另外一篇博客:https://blog.csdn.net/zgkxzx/article/details/88623498
位置:frameworks\base\services\core\java\com\android\server\VibratorService.java
public class VibratorService extends IVibratorService.Stubimplements InputManager.InputDeviceListener {native static boolean vibratorExists();native static void vibratorOn(long milliseconds);native static void vibratorOff();...@Override // Binder callpublic void vibrate(int uid, String opPkg, long milliseconds, int usageHint,IBinder token) {...startVibrationLocked(vib);}//private void startVibrationLocked(final Vibration vib) {...//开启VibrateThread线程mThread = new VibrateThread(vib);mThread.start();}}private class VibrateThread extends Thread {public void run() {...VibratorService.this.doVibratorOn(duration, uid, usageHint);}}private void doVibratorOn(long millis, int uid, int usageHint) {...//调用JNI Native本地方法vibratorOn(millis);}}}
VibratorService服务通过创建了VibrateThread线程,然后去调用Native本地端的振动器的接口vibratorOn方法
HAL层
位置:frameworks\base\services\core\jni\com_android_server_VibratorService.cpp
#include <hardware_legacy/vibrator.h>#include <stdio.h>namespace android
{static hw_module_t *gVibraModule = NULL;
static vibrator_device_t *gVibraDevice = NULL;static void vibratorInit(JNIEnv /* env */, jobject /* clazz */)
{...int err = hw_get_module(VIBRATOR_HARDWARE_MODULE_ID, (hw_module_t const**)&gVibraModule);}static void vibratorOn(JNIEnv* /* env */, jobject /* clazz */, jlong timeout_ms)
{...int err = gVibraDevice->vibrator_on(gVibraDevice, timeout_ms);}static void vibratorOff(JNIEnv* /* env */, jobject /* clazz */)
{...int err = gVibraDevice->vibrator_off(gVibraDevice);
}static const JNINativeMethod method_table[] = {{ "vibratorExists", "()Z", (void*)vibratorExists },{ "vibratorInit", "()V", (void*)vibratorInit },{ "vibratorOn", "(J)V", (void*)vibratorOn },{ "vibratorOff", "()V", (void*)vibratorOff }
};int register_android_server_VibratorService(JNIEnv *env)
{return jniRegisterNativeMethods(env, "com/android/server/VibratorService",method_table, NELEM(method_table));
}};
com_android_server_VibratorService.cpp 这个典型的HAL抽象层,通过hw_get_module获取到hw_module_t硬件模块描述结构体对象,然后对改对象进行vibratorOn或vibratorOff调用控制。
位置:hardware/libhardware/modules/vibrator/vibrator.c
#include <hardware/vibrator.h>
#include <hardware/hardware.h>static const char THE_DEVICE[] = "/sys/class/timed_output/vibrator/enable";static int sendit(unsigned int timeout_ms)
{int to_write, written, ret, fd;...//获取到驱动设备节点的文件描述符fd = TEMP_FAILURE_RETRY(open(THE_DEVICE, O_RDWR));//对设备文件进行写操作written = TEMP_FAILURE_RETRY(write(fd, value, to_write));//关闭文件close(fd);return ret;
}static int vibra_on(vibrator_device_t* vibradev __unused, unsigned int timeout_ms)
{return sendit(timeout_ms);
}static int vibra_off(vibrator_device_t* vibradev __unused)
{return sendit(0);
}static int vibra_close(hw_device_t *device)
{free(device);return 0;
}static int vibra_open(const hw_module_t* module, const char* id __unused,hw_device_t** device __unused) {vibradev->common.tag = HARDWARE_DEVICE_TAG;vibradev->common.module = (hw_module_t *) module;vibradev->common.version = HARDWARE_DEVICE_API_VERSION(1,0);vibradev->common.close = vibra_close;vibradev->vibrator_on = vibra_on;vibradev->vibrator_off = vibra_off;*device = (hw_device_t *) vibradev;return 0;
}static struct hw_module_methods_t vibrator_module_methods = {.open = vibra_open,
};struct hw_module_t HAL_MODULE_INFO_SYM = {.tag = HARDWARE_MODULE_TAG,.module_api_version = VIBRATOR_API_VERSION,.hal_api_version = HARDWARE_HAL_API_VERSION,.id = VIBRATOR_HARDWARE_MODULE_ID,.name = "Default vibrator HAL",.author = "The Android Open Source Project",.methods = &vibrator_module_methods,
};
这里是com_android_server_VibratorService.cpp文件的头文件,主要是HAL的接口描述映射关系,以及Linux用户层的驱动文件打开与控制,vibra_on与vibra_off实际上最终能调用的是sendit函数,通过open方法打开驱动节点/sys/class/timed_output/vibrator/enable进行写操作,来实现振动器Vibrator硬件设备的控制。
Linux驱动层
位置:drivers/misc/misc_sysfs.c
#include <linux/kernel.h>
...
#include <mach/gpio.h>// vibrator 对应的GPIO#define VIBRATOR_POWER_PORT (EXYNOS4_GPD(1))static unsigned char vibrator_status = 0;static void vibrate_init(void){int ret;ret = gpio_request(VIBRATOR_POWER_PORT, "GPX1");if(ret)printk("open vibrator device fail\n");//VIBRATOR_POWER_PORT引脚加入上拉配置s3c_gpio_setpull(VIBRATOR_POWER_PORT, S3C_GPIO_PULL_UP);//VIBRATOR_POWER_PORT引脚输出低电平gpio_direction_output(VIBRATOR_POWER_PORT, vibrator_status);}//读函数static ssize_t show_vibrator_onoff (struct device *dev, struct device_attribute *attr, char *buf){return vibrator_status;}//写函数static ssize_t set_vibrator_onoff (struct device *dev, struct device_attribute *attr, const char *buf, size_t count){unsigned int vibrator_status;if(!(sscanf(buf, "%u\n", &vibrator_status))) return -EINVAL;if(!vibrator_status ) {vibrator_status = 0;//VIBRATOR_POWER_PORT引脚输出低电平gpio_direction_output(VIBRATOR_POWER_PORT, GPIO_LOW);} else {vibrator_status = 1;//VIBRATOR_POWER_PORT引脚输出高电平gpio_direction_output(VIBRATOR_POWER_PORT, GPIO_HIGH);}return count;}static ssize_t show_vibrator_onoff (struct device *dev, struct device_attribute *attr, char *buf);static ssize_t set_vibrator_onoff (struct device *dev, struct device_attribute *attr, const char *buf, size_t count);static DEVICE_ATTR(vibrator_onoff, S_IRWXUGO, show_vibrator_onoff, set_vibrator_onoff);static struct attribute *control_sysfs_entries[] = {&dev_attr_vibrator_onoff.attr,NULL};static struct attribute_group control_sysfs_attr_group = {.name = NULL,.attrs = control_sysfs_entries,};
//探测函数,驱动框架第一个初始化的函数static int control_sysfs_probe(struct platform_device *pdev) {printk("vibrator probe");vibrate_init();return sysfs_create_group(&pdev->dev.kobj, &control_sysfs_attr_group);}staticint control_sysfs_remove(struct platform_device *pdev) {sysfs_remove_group(&pdev->dev.kobj, &control_sysfs_attr_group);return 0;}static struct platform_driver control_sysfs_driver = {.driver = {.name = "misc_ctl",.owner = THIS_MODULE,},.probe = control_sysfs_probe,.remove = control_sysfs_remove,};// 将vibrator注册到platform总线static int __init control_sysfs_init(void){ return platform_driver_register(&control_sysfs_driver);}static void __exit control_sysfs_exit(void){platform_driver_unregister(&control_sysfs_driver);}module_init(control_sysfs_init);module_exit(control_sysfs_exit);MODULE_DESCRIPTION("misc control driver for zgkxzx");MODULE_AUTHOR("other");MODULE_LICENSE("GPL");
Android HAL硬件抽象层与硬件系统架构相关推荐
- Android源码之Camera系统架构
2019独角兽企业重金招聘Python工程师标准>>> https://blog.csdn.net/ljsbuct/article/details/7094670 https://w ...
- Android Automotive (二)系统架构
Android Automotive (二)系统架构 前面简单介绍了一下Android Automotive 的架构,具体Android Automotive 在系统的每个层,都做了哪些东西,这里总结 ...
- 【Android 源码学习】系统架构和启动流程
Android 源码学习 系统架构和启动流程 望舒课堂 学习记录整理.以及以下参考文章的整理汇总.便于我个人的学习记录. 感谢IngresGe,Gityuan的精彩文章.为我们这些初探android系 ...
- Android开发精要1--Android系统架构
1.1 Android系统架构概况 下图是Android系统架构图,从图中可以看出,划分为三个部分: 1>应用部分 :包含在Android设备上运行的所有应用,它们是Android系统中直接面向 ...
- 如果你是12306网站架构师,你会如何设计网站的软件架构和硬件系统架构?
今年火车票网上售票的情况大家都见到了,如果让你来设计该订票网站,你会如何设计才能应对如此大规模以及高并发的情况呢? 邵辉 13 票 806 列车在线订票系统的业务逻辑比较简单,不用多说.可能的瓶颈有两 ...
- 4D毫米波雷达硬件系统架构
1 毫米波雷达与自动驾驶系统 4D毫米波雷达与车载自动驾驶系统的关系紧密,聊4D毫米波雷达,肯定抛不开自动驾驶系统.自动驾驶系统分为感知层(sense).决策层(think)和执行层(act). 感知 ...
- [转载]如果你是12306网站架构师,你会如何设计网站的软件架构和硬件系统架构?...
转载至德问网站.链接地址为:http://www.dewen.org/q/963/?ts=edm20121018&e=MzAyNjY5NzU3QHFxLmNvbQ%3D%3D 今年火车票网上售 ...
- Minieye-M3 防撞预警产品硬件系统方案---基于AR0132RGB+MTK架构
(1).产品规格 (2).硬件系统架构 camera sensor:AR0132RGB datesheet: https://docplayer.net/37244212-1-3-inch-cmos- ...
- ARM 之十五 扫盲 ARM 架构、指令集、微架构、系统架构、ARM IP、授权方式
ARM 架构的 MCU 用了好多年,进一步对于 ARM 架构也或多或少的有了一些了解.之前都是遇到啥问题直接去官网找对应的手册,一直没有系统的总结一下.是时候总结一下,以便进行下一步学习了! 总的 ...
最新文章
- jdk8飞行记录器配置
- 吴恩达老师深度学习视频课笔记:单隐含层神经网络公式推导及C++实现(二分类)
- 浅析微信支付:统一下单接口
- 安卓移动应用开发考题_Android移动应用试卷试题带答案.doc
- Linux中look命令,如何在Linux上使用look命令 | MOS86
- python多种推导式的实现
- 【Linux】一步一步学Linux——pstree命令(120)
- SQL Server T-SQL编程:数据库用户与安全设置
- 牛客网CSP-S提高组赛前集训营1题解(仓鼠的石子游戏 [博弈论] + 乃爱与城市的拥挤程度 [树上DP] + 小w的魔术扑克[dfs + 离线])
- 从云数据迁移服务看MySQL大表抽取模式
- w7设置双显示器_怎么在windows7系统下设置双显示器
- Windows Live Writer
- 零基础用阿里云服务器搭建网站的步骤
- BCD码中的8421码、2421码、5421码和余3码
- 使用Spring Validation 完成后端数据校验
- 数据中心产业深度报告:IDC产业链景气周期及投资框架分析
- 【大二下复习】新视野大学英语(第三版)第四册读写教程答案 + 期末复习翻译的部分题目
- BZOJ1189 [HNOI2007]紧急疏散evacuate
- ESP8266-Arduino编程实例-LIS3MDL磁场传感器驱动
- NFC芯片群读应用,RFID娱乐筹码、棋子FPC定制标签
热门文章
- 三中新教学楼信息系统集成方案
- 数商云医药医疗行业B2B平台:如何赋能企业数字化转型,破局传统医药通路难题
- 京东某被裁员工:虽然公司裁掉了我,但我不能裁掉我的未来!
- 百度站长平台召开百度之夜会议:打造良性搜索生态
- 想转SAP FICO顾问的必看(转)
- 鼎新TIPTOP GP5.25鼎捷易拓GP5.25视频教程26模块操作及开发
- matplotlib从折线图入门并解决中文乱码
- css3探测光圈_CSS3按钮鼠标悬浮实现光圈效果
- 【数位板常见问题】压感笔为什么没有压感了
- html取消ul下划线,css – 删除下划线:hover:before