android在framework层增加自己的service仿照GPS

不少公司在开发android产品的时候,都需要在android中增加自己的service,尤其是定制的工业用途的设备,我们公司的项目中就涉及到要增加一个service,是一个北斗通信service,具体的内容不便透露,涉及到保密。但是增加service的过程大概能描述一下,具体代码就按着不重要的来帖,大家见谅!!

其实增加自己的service不论是谁来,我想都会仿照现有service来做,在android现有service中,最简单明了的是vibrator service,其次的是location service也就是GPS,这两个service 虽然简单,但是service的架构都是相同,我们仿照的目标就是要这样,明了的架构,往里面填东西就是体力活了。下面我们从下往上一一来看每个步骤。

1.kernel层

我们的硬件连接到设备上一个串口,因此kernel层我们就不用什么改动。当然如果你们添加的硬件设备需要驱动的话,自己加进去就是了,这里不多说了。

2.HAL层

我们先找到了GPS的HAL层代码 \android\hardware\imx\libgps中一共两个文件,仔细分析来看,这两个文件主要功能是生成一个动态链接库,向下与硬件通信,向上为系统提供访问的接口函数,知道了这个,我们就明白了HAL层大概的功能,我们的工作就是选一个适合自己硬件的方法实现这个功能。

我们的硬件是一个串口通信的设备,无非就是可以由上层控制来发送命令和接受命令,因此我选的是串口通信很常见的方式: 每条发送命令都单独写一个函数,有上层来控制发送哪条。接收命令就启动一个接收线程,每当收到数据后,进行一系列的判定,把有效的数据传送到上层。

下面我们来看具体代码在android\hardware\imx\librd目录中:

首先是我们与硬件通信的几个函数:

01. static const RDInterface  goldtelrdInterface = {
02. sizeof(RDInterface),
03. goldtel_rd_init,
04. goldtel_rd_close,
05. goldtel_rd_send_XTZJ,
06. goldtel_rd_send_ICJC,
07. goldtel_rd_send_SJSC,
08. goldtel_rd_send_DWSQ,
09. goldtel_rd_send_BBDQ,
10. goldtel_rd_send_YHZL_SJTX,
11. goldtel_rd_send_TXSQ,
12. };

具体的函数功能就不多说了,反正就是发送命令初始化和关闭。当上层打开这个service的时候会调用goldtel_rd_init()这个函数,因此在这个函数里面我们要实现一系列的初始化功能,包括打开设备电源,打开串口,创建接收进程等等。具体代码:

01. static int goldtel_rd_init(RDCallbacks* callbacks)
02. {
03. RdState*  s = _rd_state;
04. //lijianzhang
05. write_sysfs("/sys/devices/platform/bd_power/enable_rdss","1",1); //给设备上电
06. usleep(1500000);
07. if (!s->init)
08. rd_state_init(s, callbacks);//进行一系列的初始化 注意这里的一个参数callbacks,
09. //这是一些回调函数,是在jni层实现的,传到底层来运行
10. //android很多都是这么来实现,如果以后看别的代码看到
11. //类似方式就不要慌乱,去jni层里肯定能找到
12.  
13. if (s->fd < 0)
14. return -1;
15.  
16. rd_state_start(s); //开始工作
17.  
18. return 0;
19. }

然后是rd_state_init()

01. static void
02. rd_state_init( RdState*  state, RDCallbacks* callbacks )
03. {
04. .................
05. 一系列初始化
06. 。。。。。。。。。。。。。。。。。。。
07. state->thread = callbacks->create_thread_cb( "rd_state_thread", rd_state_thread, state );//这个函数里最主要的功能就是创建接收线程
08.  
09. 。。。。。。。。。。。。。。。。。。。
10. 。。。。。。。。。。。。。。。。。。。
11. }
下面来看接收线程里的东西:
这里面用到了很多的epoll通信机制,其实逻辑很简单一看就明白,下面把代码贴出来,大家给个参考指正

001. static void
002. rd_state_thread( void*  arg )
003. {
004. RdState*   state = (RdState*) arg;
005. NmeaReader  reader[1];
006. int         epoll_fd   = epoll_create(2);
007. int         started    = 0;
008. int         rd_fd     = state->fd;
009. int         control_fd = state->control[1];
010.  
011. nmea_reader_init( reader );
012.  
013. // 注册epoll 文件
014. epoll_register( epoll_fd, control_fd );
015. epoll_register( epoll_fd, rd_fd );
016.  
017. LOGE("RD thread running");
018.  
019. // now loop
020. for (;;) {
021. struct epoll_event   events[2];
022. int                  ne, nevents;
023.  
024. nevents = epoll_wait( epoll_fd, events, 2, -1 ); //等待epoll消息
025. if (nevents < 0) {
026. if (errno != EINTR)
027. E("epoll_wait() unexpected error: %s", strerror(errno));
028. continue;
029. }
030. D("rd thread received %d events", nevents);
031. for (ne = 0; ne < nevents; ne++) {   //处理每条消息
032. if ((events[ne].events & (EPOLLERR|EPOLLHUP)) != 0) {
033. E("EPOLLERR or EPOLLHUP after epoll_wait() !?");
034. return;
035. }
036. if ((events[ne].events & EPOLLIN) != 0) {
037. int  fd = events[ne].data.fd;
038.  
039. if (fd == control_fd)   //如果这个消息是控制命令的话,这里的控制命令其实就两条,
040. //服务开始和服务结束,下面就是分别对着两条命令进行处理
041. {
042. char  cmd = 255;
043. int   ret;
044. D("rd control fd event");
045. do {
046. ret = read( fd, &cmd, 1 );
047. while (ret < 0 && errno == EINTR);
048.  
049. if (cmd == CMD_QUIT) {  //服务退出
050. if (started) {
051.  
052. started = 0;
053. nmea_reader_set_DWXX_callback(reader,NULL);
054. nmea_reader_set_BBXX_callback(reader,NULL);
055. nmea_reader_set_FKXX_callback(reader,NULL);
056. nmea_reader_set_ICXX_callback(reader,NULL);
057. nmea_reader_set_ZJXX_callback(reader,NULL);
058. nmea_reader_set_TXHZ_callback(reader,NULL);
059. nmea_reader_set_TXXX_callback(reader,NULL);
060. }
061. return;
062. }
063. else if (cmd == CMD_START) {    //服务开始
064. if (!started) {
065. LOGE("rd_state_thread start!");
066. started = 1;
067. nmea_reader_set_DWXX_callback(reader,state->callbacks.dwxx_cb);
068. nmea_reader_set_BBXX_callback(reader,state->callbacks.bbxx_cb);
069. nmea_reader_set_FKXX_callback(reader,state->callbacks.fkxx_cb);
070. nmea_reader_set_ICXX_callback(reader,state->callbacks.icxx_cb);
071. nmea_reader_set_ZJXX_callback(reader,state->callbacks.zjxx_cb);
072. nmea_reader_set_TXHZ_callback(reader,state->callbacks.txhz_cb);
073. nmea_reader_set_TXXX_callback(reader,state->callbacks.txxx_cb);
074. }
075. }
076.  
077. }
078. else if (fd == rd_fd)   //如果是串口通信的消息
079. {
080. // LOGE("start read data");
081.  
082. char  buff[32];
083.  
084. for (;;) {
085. int  nn, ret;
086.  
087. ret = read( fd, buff, sizeof(buff) );   //从串口中读出数据
088. if (ret < 0) {
089. if (errno == EINTR)
090. continue;
091. if (errno != EWOULDBLOCK)
092. E("error while reading from gps daemon socket: %s:", strerror(errno));
093. break;
094. }
095.  
096. for (nn = 0; nn < ret; nn++)
097.  
098. {     
099. //LOGE("start read data %02X",buff[nn]);                     
100. nmea_reader_addc( reader, buff[nn] );    //判定数据有效性并进行处理
101. }
102. }
103.  
104. }
105. else
106. {
107. E("epoll_wait() returned unkown fd %d ?", fd);
108. }
109. }
110. }
111. }
112.  
113. }

下面重要的函数就是nmea_reader_addc( NmeaReader* r, int c ) 这里作为涉密内容不做过多的说明了,明白就是判定命令并与上层通信就可以了。

进程创建完成了,hal层基本功能就完成了,下一步就是将这些功能声称一个.so动态链接库,方法就是下面的代码:

01. static const RDInterface* get_rd_hardware_interface()
02. {
03. return &goldtelrdInterface;
04. }
05.  
06. static int open_rd(const struct hw_module_t* module, char const* name,
07. struct hw_device_t** device)
08. {
09. struct rd_device_t *dev = malloc(sizeof(struct rd_device_t));
10. memset(dev, 0, sizeof(*dev));
11.  
12.  
13. dev->common.tag = HARDWARE_DEVICE_TAG;
14. dev->common.version = 0;
15. dev->common.module = (struct hw_module_t*)module;
16. dev->get_rd_interface = get_rd_hardware_interface;
17.  
18. *device = (struct hw_device_t*)dev;
19. return 0;
20. }
21.  
22.  
23. static struct hw_module_methods_t rd_module_methods = {
24. .open = open_rd
25. };
26.  
27. const struct hw_module_t HAL_MODULE_INFO_SYM = {
28. .tag = HARDWARE_MODULE_TAG,
29. .version_major = 1,
30. .version_minor = 0,
31. .id = RD_HARDWARE_MODULE_ID,
32. .name = "Real6410 rd Module",
33. .author = "The <a href="http://www.it165.net/pro/ydad/" target="_blank" class="keylink">Android</a> Open Source Project",
34. .methods = &rd_module_methods,
35. };

3.JNI层

动态链接库生成完了,下面就到了framework层,我们找到了location service的代码在目录\android\frameworks\base\services\jni\中功能就是打开这个动态链接库然后,向java层提供函数接口,功能很简单我们直接来看我写的代码在android\\frameworks\base\services\jni\com_android_server_rdmessage_RDMessageDispatch.cpp中

首先是打开动态链接库

01. static const RDInterface* get_rd_interface() {
02. int err;
03. hw_module_t* module;
04. const RDInterface* interface = NULL;
05.  
06. err = hw_get_module(RD_HARDWARE_MODULE_ID, (hw_module_t const**)&module);
07. if (err == 0) {
08. hw_device_t* device;
09. err = module->methods->open(module, RD_HARDWARE_MODULE_ID, &device);
10. if (err == 0) {
11. rd_device_t* rd_device = (rd_device_t *)device;
12. interface = rd_device->get_rd_interface(rd_device);
13. }
14. }
15.  
16. return interface;
17. }
最后的是想上层提供的函数接口

01. static JNINativeMethod sMethods[] = {
02. /* name, signature, funcPtr */
03. {"class_init_native""()V", (void *)android_rdmessage_RDMessageDispatch_class_init_native},
04. {"native_is_supported","()Z",(void*)android_rdmessage_RDMessageDispatch_is_supported},
05. {"native_BDMessage_start""()Z", (void*)android_rdmessage_RDMessageDispatch_native_BDMessage_start},
06. {"native_close","()V",(void*)android_rdmessage_RDMessageDispatch_native_close},
07. {"native_sendXTZJ""(I)Z", (void*)android_rdmessage_RDMessageDispatch_native_sendXTZJ},
08. {"native_sendICJC""()Z", (void*)android_rdmessage_RDMessageDispatch_native_sendICJC},
09. {"native_sendSJSC""(I)Z", (void*)android_rdmessage_RDMessageDispatch_native_sendSJSC},
10. {"native_sendDWSQ""(ZZ)Z", (void*)android_rdmessage_RDMessageDispatch_native_sendDWSQ},
11. {"native_sendBBDQ""()Z", (void*)android_rdmessage_RDMessageDispatch_native_sendBBDQ},
12. {"native_sendYHZL_SJTX""(II)Z", (void*)android_rdmessage_RDMessageDispatch_native_sendYHZL_SJTX},
13. {"native_SendBDMessage""(I[BIIZ)Z", (void*)android_rdmessage_RDMessageDispatch_native_SendBDMessage},
14. {"read_TXXX_message""([BI)I", (void*)android_rdmessage_RDMessageDispatch_read_TXXX_message},
15. {"read_DWXX_message","([B[B[B[B[B)V",(void*)android_rdmessage_RDMessageDispatch__read_DWXX_message},   
16. };
中间就是实现这两者之间的转换,我们来说转换过程中比较重要的几点首先是发送命令,很简单,就是直接调用动态链接库中提供的发送函数,看代码

01. static jboolean  android_rdmessage_RDMessageDispatch_native_sendICJC
02. (JNIEnv *env, jobject obj)
03. {
04.  
05. if (!sRdInterface)
06. return false;
07.  
08. if(sRdInterface->rd_send_ICJC()!=0)
09. return false;
10.  
11. return true;
12.  
13. }

然后是,收到串口数据,传送的上层的方法,这里就涉及到了刚才提到的回调函数,在这里实现但是在HAL层执行,函数含简单就是调用函数将数据发送上去,看代码

01. static void ZJXX_callback(ZJXXInfo *zjxx)
02. {
03. JNIEnv* env = <a href="http://www.it165.net/pro/ydad/" target="_blank" class="keylink">Android</a>Runtime::getJNIEnv();
04.  
05. env->CallVoidMethod(mCallbacksObj,method_reportZJXX,zjxx->UserId,zjxx->ICStatus,
06. zjxx->YJStatus,zjxx->DCStatus,zjxx->RZStatus,zjxx->bs1Status,zjxx->bs2Status,
07. zjxx->bs3Status,zjxx->bs4Status,zjxx->bs5Status,zjxx->bs6Status);
08. checkAndClearExceptionFromCallback(env, __FUNCTION__);
09. }

其他的就不多说了下面来看framework层

4. framework层

我们看到location service的代码在android\frameworks\base\services\java\com\android\server\LocationManagerService.java

android\frameworks\base\services\java\com\android\server\location目录 android\\frameworks\base\location\java\android\location目录中

分析一下架构,就是向下接口JNI层的 代码,在此基础上封装service实现函数,最后在servicemanager中运行这个服务,还有增加这个服务的aidl文件,以便于所有的app都能访问到。所以我们所做的工作也是这些,其实比较简单,主要是为界面提供支持,比如更新状态栏北斗信号强度等等,这里就不再贴代码了,大家可以自己看gps是怎么做的仿照来就行。

实现了这些函数最后要在android\frameworks\base\services\java\com\android\server\SystemServer.java中增加

1. try {        //启动这个service
2. Slog.i(TAG, "RdMessage Manager");
3. rdmessage = new RdMessageManagerService(context);
4. ServiceManager.addService(Context.RD_MESSAGE_SERVICE, rdmessage);
5. catch (Throwable e) {
6. reportWtf("starting RdMessage Manager", e);
7. }

1. try {
2. if (rdmessageF != null) rdmessageF.systemReady();   //告诉系统服务启动完成
3. catch (Throwable e) {
4. reportWtf("making RdMessage Service ready", e);
5. }

增加这些代码后就系统就可以启动服务了,
最后在\frameworks\base\core\java\android\os\增加IRdMessageManager.aidl, RdMessageManager.java这两个文件,是提供给上层使用的短信服务。

到了这里整个service添加就完成了,我们就可以通过app来访问这个service了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值