Android 灯光系统开发

本文基于Android5.0开发APP控制硬件LED亮灭,实现应用程序、应用程序框架层、系统运行时层、硬件抽象层、linux字符设备驱动的开发过程。

 

上图描述了我们Led实例的框架层次:

l  LedDemo.java:是我们写的Android应用程序

l  LedService.java:是根据Led HAL封装的Java框架层的API,主要用于向应用层提供框架层API,它属于Android的框架层

l  libled_runtime.so:由于Java代码不能访问HAL层,该库是LedService.java对应的本地代码部分

l  led.default.so:针对led硬件的HAL代码

LedDemo通过LedService提供的框架层API访问Led设备,LedService对于LedDemo应用程序而言是Led设备的服务提供者,LedService运行在Dalvik中没有办法直接访问Led硬件设备,它只能将具体的Led操作交给本地代码来实现,通过JNI来调用Led硬件操作的封装库libled_runtime.so,由HAL Stub框架可知,在libled_runtime.so中首先查找注册为led的硬件设备module,找到之后保存其操作接口指针在本地库中等待框架层LedService调用。led.default.so是HAL层代码,它是上层操作的具体实施者,它并不是一个动态库(也就是说它并没有被任何进程加载并链接),它只是在本地代码查找硬件设备module时通过ldopen”杀鸡取卵”找module,返回该硬件module对应的device操作结构体中封装的函数指针。

其调用时序如下:

 

Led HAL实例代码分析

我们来看下led实例的目录结构:

 

主要文件如下:

com.hello.LedService.cpp:它在frameworks/services/jni目录下,是的Led本地服务代码

led.c:HAL代码

led.h:HAL代码头文件

LedDemo.java:应用程序代码

LedService.java:Led框架层服务代码

在Android的源码目录下,框架层服务代码应该放在frameworks/services/java/包名/目录下,由Android的编译系统统一编译生成system/framework/services.jar文件,由于我们的测试代码属于厂商定制代码,尽量不要放到frameworks的源码树里,我将其和LedDemo应用程序放在一起了,虽然这种方式从Android框架层次上不标准。

另外,本地服务代码的文件名要和对应的框架层Java代码的名字匹配(包名+类文件名,包目录用“_“代替)。有源码目录里都有对应的一个Android.mk文件,它是Android编译系统的指导文件,用来编译目标module。

 

1)        Android.mk文件分析

先来看下led源码中①号Android.mk:

[plain] view plain copy

  1. include $(call all-subdir-makefiles)  

代码很简单,表示包含当前目录下所有的Android.mk文件

先来看下led_app目录下的③号Android.mk:

[plain] view plain copy

  1. # 调用宏my-dir,这个宏返回当前Android.mk文件所在的路径  
  2. LOCAL_PATH:= $(call my-dir)                                       
  3.   
  4. # 包含CLEAR_VARS变量指向的mk文件build/core/clear_vars.mk,它主要用来清除编译时依赖的编译变量  
  5. include $(CLEAR_VARS)                                      
  6.   
  7. # 指定当前目标的TAG标签,关于其作用见前面Android编译系统章节  
  8. LOCAL_MODULE_TAGS := user  
  9.   
  10. # 当前mk文件的编译目标模块  
  11. LOCAL_PACKAGE_NAME := LedDemo  
  12.   
  13. # 编译目标时依赖的源码,它调用了一个宏all-java-files-under,该宏在build/core/definitions.mk中定义  
  14. # 表示在当前目录下查找所有的java文件,将查找到的java文件返回  
  15. LOCAL_SRC_FILES := $(callall-java-files-under, src)  
  16.   
  17. # 在编译Android应用程序时都要指定API level,也就是当前程序的编译平台版本  
  18. # 这里表示使用当前源码的版本  
  19. LOCAL_SDK_VERSION := current  
  20.   
  21. # 最重要的就是这句代码,它包含了一个文件build/core/package.mk,根据前面设置的编译变量,编译生成Android包文件,即:apk文件  
  22. include $(BUILD_PACKAGE)  

上述代码中都加了注释,基本上每一个编译目标都有类似上述的编译变量的声明:

LOCAL_MODULE_TAGS

LOCAL_PACKAGE_NAME

LOCAL_SRC_FILES

由于所有的Android.mk最终被编译系统包含,所以在编译每个目标模块时,都要通过LOCAL_PATH:= $(call my-dir)指定当前目标的目录,然后调用include $(CLEAR_VARS)先清除编译系统依赖的重要的编译变量,再生成新的编译变量。

让我们来看看LedDemo目标对应的源码吧。

2)        LedDemo代码分析

学习过Android应用的同学对其目录结构很熟悉,LedDemo的源码在src目录下。

@ led_app/src/com/farsight/LedDemo.java:

[java] view plain copy

  1. package com.hello;  
  2.   
  3.  import com.hello.LedService;  
  4.   
  5.  import com.hello.R;  
  6.   
  7.  importandroid.app.Activity;  
  8.   
  9.  importandroid.os.Bundle;  
  10.   
  11.  importandroid.util.Log;  
  12.   
  13.  importandroid.view.View;  
  14.   
  15.  import android.view.View.OnClickListener;  
  16.   
  17.  importandroid.widget.Button;  
  18.   
  19.    
  20.   
  21.  public classLedDemo extends Activity {  
  22.      privateLedService led_svc;  
  23.      private Buttonbtn;  
  24.      private booleaniflag = false;  
  25.      private Stringtitle;  
  26.   
  27.       /** Calledwhen the activity is first created. */  
  28.      @Override  
  29.      public void onCreate(Bundle savedInstanceState) {  
  30.         super.onCreate(savedInstanceState);  
  31.         setContentView(R.layout.main);  
  32.   
  33.         Log.i("Java App""OnCreate");  
  34.          led_svc =new LedService();  
  35.          btn =(Button) this.findViewById(R.id.Button01);  
  36.         this.btn.setOnClickListener(new OnClickListener() {  
  37.             public void onClick(View v) {  
  38.                 Log.i("Java App""btnOnClicked");  
  39.                 if (iflag) {  
  40.                     title = led_svc.set_off();  
  41.                     btn.setText("Turn On");  
  42.                     setTitle(title);  
  43.                     iflag = false;  
  44.                 } else {  
  45.                     title = led_svc.set_on();  
  46.                     btn.setText("Turn Off");  
  47.                     setTitle(title);  
  48.                     iflag = true;  
  49.                 }  
  50.              }  
  51.          });  
  52.      }  
  53.  }  

代码很简单,Activity上有一个按钮,当Activity初始化时创建LedService对象,按钮按下时通过LedService对象调用其方法set_on()和set_off()。

 

3)        LedService代码分析

我们来看下LedService的代码:

@led_app/src/com/farsight/LedService.java:

[java] view plain copy

  1. package com.hello;  
  2. import android.util.Log;  
  3.   
  4. public class LedService {  
  5.   
  6.     /* 
  7.      * loadnative service. 
  8.      */  
  9.     static {         // 静态初始化语言块,仅在类被加载时被执行一次,通常用来加载库  
  10.         Log.i ("Java Service" , "Load Native Serivce LIB" );  
  11.        System.loadLibrary ( "led_runtime" );  
  12.     }  
  13.   
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值