android在framework层增加自己的service仿照GPS
来源:互联网 发布:golang syscall说明 编辑:程序博客网 时间:2024/05/20 06:56
其实增加自己的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了。
- android在framework层增加自己的service---仿照GPS
- android在framework层增加自己的service仿照GPS
- android 在framework层增加服务后编译报错
- Android Service Framework (Native层的一个例子)
- Android Framework层的Service死锁问题分析
- How to show a toast in Android Framework service. 如何在Framework层显示toast.
- Android Framework GPS
- android关于GPS hal层的分析
- android关于GPS hal层的分析
- android关于GPS hal层的分析
- android关于GPS hal层的分析
- android关于GPS hal层的分析
- Android Framework层的理解
- Android Framework:Binder(6)-Java层Service的注册及跨进程调用
- ANDROID gps应用层
- Android framework层编写service(实验验证后修订)
- Android framework层编写service(实验验证后修订)
- GPS在Android的使用
- 用tomcat部署web工程
- HTML常用标签及属性
- coj 1006: SAW 运气题,输出一个大写字母,一直提交。
- CSS (一)
- Ubuntu14.04 apt-fast加速apt-get
- android在framework层增加自己的service仿照GPS
- coj 1067: 1 VS 1
- 黑马程序员--java概述
- 简单测试一下go(golang) 和libtask 协程的切换效率
- 矩形合并
- 学习hadoop(3)join日志
- ubuntu安装redis
- 黑马程序员———面向对象之多态、抽象类和接口
- Java设计模式之——单例模式