作者:唐老师,华清远见嵌入式学院讲师。

1. Sensor的概念

Sensor即传感器,在当前智能手机上大量存在:G-Sensor、LightsSensor、 ProximitySensor、TemperatureSensor等,其作为Android系统的一个输入设备,对于重视用户体验的移动设备来说是必 不可少的。Sensor虽然是一个输入设备,但是它又不同于触摸屏,键盘,按键等这些常规的输入设备,因为Sensor的数据输入从传感器硬件到设备的, 而常规的输入设备是从用户到设备的,比如:温度传感器用于感知温度的变化,采样传感器数据上报给设备。而传感器硬件的工作与否,采样精度是由用户来控制 的,所以对应Sensor而言是其工作方式是双向的,即:控制硬件的控制流,硬件上报的数据流。这也决定了Sensor的框架不同与触摸屏等常规输入子系 统。

本章节主要研究的Sensor框架代码与SensorHAL的实现细节,一切还是从Sensor框架开始,首先来回顾下Led HAL的实现框架。

Led HAL是我们自己实现的,主要分为四部分:
        Led App:Led的应用程序
        Led Service框架:Led应用的API提供者
        LedService本地:LedService服务的本地实现,上层与底层的通信转化接口
        Led HAL Stub:HAL层代码,具体硬件驱动操作接口

很明显,我们写的Led HAL代码是典型的控制流,反馈结果就是Led灯的亮与灭,它的架构不适用于Sensor架构,具体有如下几点:
        l Led是单纯的控制流,而Sensor是控制流与数据流
        Sensor的数据流不是实时的,而是有采样速率,并且数据不是连续的,阻塞在读取硬件设备数据上,只有数据得到才返回。
        l Sensor是提供给所有传感器的通用框架,不是针对某一特定硬件的架构
        Sensor包含多种类型,在上层和底层都有对Sensor具体类型的屏蔽,让它通用所有传感器。
        l Sensor的服务不是由应用程序创建启动的,应该是伴随系统启动的
        任何一个应用程序里都可以使用Sensor服务,这决定了Sensor服务应该伴随系统启动。

2. Sensor的框架分析

本节是本系列第一个分析的具体设备的框架,从Android SensorService的注册启动开始,到应用程序获得SensorManager注册传感器监听器,详细分析从应用层到Java框架层再到本地代码,最后调用HAL层全部过程。

1.1 Sensor服务的启动

由前面Android启动流程章节可知,Zygote启动起来后,运行的每一个Java进程是SystemServer,它用来启动并管理所有的Android服务:

[cpp] view plaincopyprint?

   1. public static void main(String[] args) {
           2.  …
           3.    System.loadLibrary("android_servers");
           4.    init1(args);
           5. }

由SystemServer的main方法可知,其加载了libandroid_servers.so的库,并且调用了init1()方法。
我们通过下面的命令来找到该库的编译目录:

[plain] view plaincopyprint?

   1. find ./frameworks/base –name Android.mk –exec grep –l libandroid_servers{}\;

通过打印的信息知道,其对应的源码目录在:frameworks/base/services/jni/下,其实Android框架层的代码的特点就是Java目录下存放的是对应的Java框架代码,对应的jni目录下是对应的本地代码。

在这个目录所有的代码最重要的就是:com_android_server_SystemServer.cpp:

[cpp] view plaincopyprint?

   1. namespace android {
           2.
           3. extern "C" int system_init();
           4. static void android_server_SystemServer_init1(JNIEnv*env, jobject clazz)
           5. {
           6. system_init();
           7. }
           8. /*
           9. * JNIregistration.
           10. */
           11. static JNINativeMethod gMethods[] = {
           12. /* name,signature, funcPtr */
           13. {"init1", "([Ljava/lang/String;)V", (void*) android_server_SystemServer_init1},
           14. };
           15.
           16. int register_android_server_SystemServer(JNIEnv* env)
           17. {
           18. returnjniRegisterNativeMethods(env, "com/android/server/SystemServer",
           19. gMethods, NELEM(gMethods));
           20. }
           21.
           22. }; // namespace android

代码不是很多,也比较好读,调用jniRegisterNativeMethods方法注册SystemServer的Java方法也本地方法映射关系,jniRegisterNativeMethods是一个本地方法的注册Helper方法。

SystemServer.java在加载了libandroid_servers.so库之后,调用了
init1(),通过上面代码中的映射关系可知,它调用了本地的android_server_SystemServer_init1方法,该方法直接调
用system_init(),其实现在frameworks/base/cmds/system_server/library
/system_init.cpp中实现:

[cpp] view plaincopyprint?

   1. extern "C" status_t system_init()
           2. {
           3. LOGI("Entered system_init()");
           4. sp<ProcessState> proc(ProcessState::self());
           5. sp<IServiceManager> sm = defaultServiceManager();
           6. LOGI("ServiceManager: %p\n", sm.get());
           7. sp<GrimReaper> grim = new GrimReaper();
           8. sm->asBinder()->linkToDeath(grim, grim.get(), 0);
           9.
           10. charpropBuf[PROPERTY_VALUE_MAX];
           11. property_get("system_init.startsurfaceflinger", propBuf,"1");
           12. if(strcmp(propBuf, "1") == 0) {
           13. // Startthe SurfaceFlinger
           14. SurfaceFlinger::instantiate();
           15. }
           16.
           17. property_get("system_init.startsensorservice", propBuf,"1");
           18. if(strcmp(propBuf, "1") == 0) {
           19. // Startthe sensor service
           20. SensorService::instantiate();
           21. }
           22. LOGI("Systemserver: starting Android runtime.\n");
           23. AndroidRuntime* runtime = AndroidRuntime::getRuntime();
           24.
           25. LOGI("System server: starting Android services.\n");
           26. JNIEnv* env =runtime->getJNIEnv();
           27. if (env ==NULL) {
           28. returnUNKNOWN_ERROR;
           29. }
           30.
           31. jclass clazz= env->FindClass("com/android/server/SystemServer");
           32. if (clazz ==NULL) {
           33. returnUNKNOWN_ERROR;
           34. }
           35.
           36. jmethodIDmethodId = env->GetStaticMethodID(clazz, "init2","()V");
           37. if (methodId== NULL) {
           38. returnUNKNOWN_ERROR;
           39. }
           40. env->CallStaticVoidMethod(clazz, methodId);
           41.
           42. LOGI("System server: entering thread pool.\n");
           43. ProcessState::self()->startThreadPool();
           44. IPCThreadState::self()->joinThreadPool();
           45. LOGI("System server: exiting thread pool.\n");
           46. }

如果了解Binder机制的话,应该知道,sp proc(ProcessState::self())打开Binder驱动并会创建一个ProcessState对象并维持当前进程的Binder通信的服务器端。

如果系统属性里配置了system_init.startsensorservice 属性为1,则通过SensorService::instantiate()启动Sensor服务。

对于初学者最头疼的就是追面向对象代码中的重载,重写的代码
了,SensorService::instantiate()调用的是其父类的方法,我们可以通过子类的定义找其继承关系,然后顺着继承关系再来查找方
法的实现,如果在子类里和父类里都有方法的实现,那么看参数的匹配,如果参数都相互匹配,那么就是所谓的重写,调用的是子类的方法。
SensorService的定义如下:

@frameworks/base/services/sensorservice/SensroService.h

[cpp] view plaincopyprint?

   1. class SensorService :
           2. publicBinderService,
           3. publicBnSensorServer,
           4. protectedThread
           5. {

通过SensorService的定义可知,在当前类里没有instantiate方法的声明,说明其调用
的是父类的方法,其继承了BinderService,BnSensorServer,Thread类(难道SensorService是一个线
程??),顺着继承关系找,在BinderService里可以找到instantiate方法的声明。

@frameworks/base/include/binder/BinderService.h

[cpp] view plaincopyprint?

   1. template
           2.
           3. class BinderService
           4. {
           5. public:
           6. static status_t publish() {
           7. sp sm(defaultServiceManager());
           8. returnsm->addService(String16(SERVICE::getServiceName()), new SERVICE());
           9. }
           10.
           11. static void publishAndJoinThreadPool() {
           12. sp proc(ProcessState::self());
           13. sp sm(defaultServiceManager());
           14. sm->addService(String16(SERVICE::getServiceName()), new SERVICE());
           15. ProcessState::self()->startThreadPool();
           16. IPCThreadState::self()->joinThreadPool();
           17. }
           18.
           19. static void instantiate() { publish(); }
           20.
           21. static status_t shutdown() {
           22. return NO_ERROR;
           23. }
           24. };

通过上面代码分析可知,instantiate方法创建了SensorService并通过addService将自己新创建的SensorService服务添加到Android服务列表里了。

Ok,那我们来到SensorService服务中。

@frameworks/base/services/sensorservice/SensorService.cpp

[cpp] view plaincopyprint?

   1. SensorService::SensorService()
           2. :mInitCheck(NO_INIT)
           3. {
           4. }
           5.
           6. void SensorService::onFirstRef()
           7. {
           8. LOGD("nuSensorService starting...");
           9. SensorDevice& dev(SensorDevice::getInstance());
           10. …

SensorService的构造方法比较简单,初始化了成员变量mInitCheck为NO_INIT。

要注意构造方法后面的onFirstRef方法,它是Android系统里引用计数系统里的一个方法。当RefBase的子类对象被第一次强引用时自动调用其方法,所以当第一次使用SensorService服务里该方法被自动回调。
形如:

[cpp] view plaincopyprint?

   1. sp< ISensorServer> sm(mSensorService);

注:关于引用计数系统,如果读者不太了解,请参考邓凡平老师的:深入理解:Android系统核心 卷I中的三板斧部分。

SensorService的启动到此暂停,等待上层应用的使用SensorService服务并调用onFirstRef方法。

文章来源:华清远见嵌入式学院,原文地址:http://www.embedu.org/Column/Column770.htm

更多相关嵌入式免费资料查看华清远见讲师博文>>

深入浅出 - Android系统移植与平台开发(十一) - Sensor HAL框架分析之一的更多相关文章

  1. 深入浅出 - Android系统移植与平台开发(一)

    深入浅出 - Android系统移植与平台开发(一) 分类: Android移植2012-09-05 14:16 16173人阅读 评论(12) 收藏 举报 androidgitgooglejdkub ...

  2. 深入浅出 - Android系统移植与平台开发(十) - led HAL简单设计案例分析

    作者:唐老师,华清远见嵌入式学院讲师. 通过前两节HAL框架分析和JNI概述,我们对Android提供的Stub HAL有了比较详细的了解了,下面我们来看下led的实例,写驱动点亮led灯,就如同写程 ...

  3. 深入浅出 - Android系统移植与平台开发(十一)- Android系统的定制(瘋耔修改篇一)

    首先非常感谢原文作者为我们提供的知识库,因为有你们的贡献,我们的开发难度更显简单 原文 :   http://blog.csdn.net/mr_raptor/article/details/30113 ...

  4. 深入浅出 - Android系统移植与平台开发(三)- 编译并运行Android4.0模拟器

    作者:唐老师,华清远见嵌入式学院讲师. 1.   编译Android模拟器 在Ubuntu下,我们可以在源码里编译出自己的模拟器及SDK等编译工具,当然这个和在windows里下载的看起来没有什么区别 ...

  5. 深入浅出 - Android系统移植与平台开发(五)- 编译Android源码(转)

    2.3编译Android源码 Android源码体积非常庞大,由Dalvik虚拟机.Linux内核.编译系统.框架代码.Android定制C库.测试套件.系统应用程序等部分组成,在编译Android源 ...

  6. 深入浅出 - Android系统移植与平台开发(十)- Android编译系统与定制Android平台系统(瘋耔修改篇二)

    第四章.Android编译系统与定制Android平台系统 4.1Android编译系统 Android的源码由几十万个文件构成,这些文件之间有的相互依赖,有的又相互独立,它们按功能或类型又被放到不同 ...

  7. 深入浅出 - Android系统移植与平台开发(二) - 准备Android开发环境

    作者:唐老师,华清远见嵌入式学院讲师. 编译Android源码 关于android系统的编译,Android的官方网站上也给出了详细的说明.http://source.android.com/sour ...

  8. 深入浅出 - Android系统移植与平台开发(六)- 为Android启动加速

    作者:唐老师,华清远见嵌入式学院讲师. Android的启动速度一直以来是他的诟病,虽然现在Android设备的硬件速度越来越快,但是随着新 版本的出现,其启动速度一直都比较慢,当然,作为程序员,我们 ...

  9. 深入浅出 - Android系统移植与平台开发(七)- 初识HAL

    作者:唐老师,华清远见嵌入式学院讲师. 1. HAL的module与stub HAL(Hardware AbstractLayer)硬件抽象层是Google开发的Android系统里上层应用对底层硬件 ...

随机推荐

  1. Python 遍历文件,字符串操作

    写一个简单的脚本,循环遍历单层文件夹,检查源代码中是否有一些特殊的类. import os import codecs dirroot = "......" line_num = ...

  2. [JavaCore] 取得类的字节码、取得类的装载器

    三种方式取得类的字节码: 1. 类名.class BranchInfoService.class 2. 对象名.getClass() branchInfoService.getClass() 3. C ...

  3. Android LayoutInflater详解 (转)

    在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById().不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例 ...

  4. NDK-gdb

    http://www.gnu.org/software/gdb/download/ http://mhandroid.wordpress.com/2011/01/23/using-eclipse-fo ...

  5. 【MyEcplise SVN】myEcplise上安装SVN的多种方式

    第一种:SVN的在线安装 1.打开MyEclipse,找到顶部菜单栏 Help(帮助)-Install from Site-(从网站安装),如下图 2. 然后: 点击Install from Site ...

  6. 【maven】 在 MyEcplise上使用maven搭建Web项目

    二.在My Ecplise上使用Maven搭建Web项目 1.新建一个maven项目   2.create一个简单的骨架 3.就像在ecplise中一样设置项目的以下配置   4.新创建的项目结构如下 ...

  7. minix3(一)安装以及编辑文件

    作为一条通信狗,最近开始自学操作系统.听说用MINIX3学操作系统很好,就决定跟UCSB的课程试试. 首先在虚拟机上安装MINIX3. 开始用的VM Station,按照百度文库里安装minix3的教 ...

  8. SoapUI接口测试之实战运用操作(五)

    SoapUI接口测试之实战运用操作(五)

  9. 解决android expandablelistview 里面嵌入gridview行数据重复问题

    最近做了一个“csdn专家博客App” 当然了是android版本,在专家浏览页面,我才用了expandablelistview 组件来显示专家分类,每个分类点击之后可以显示专家的头像和名字. 很简单 ...

  10. HDU 2222 Keywords Search (AC自动机)

    题意:给你一些模式串,再给你一串匹配串,问你在匹配串中出现了多少种模式串,模式串可以相同 AC自动机:trie树上进行KMP.首先模式串建立trie树,再求得失配指针(类似next数组),其作用就是在 ...