[置顶] Android开发之serviceManager分析
Android 开发之serviceManager分析
在Android系统中用到最多的通信机制就是Binder,Binder主要由Client、Server、ServiceManager和Binder驱动程序组成。其中Client、Service和ServiceManager运行在用户空间,而Binder驱动程序运行在内核空间。核心组件就是Binder驱动程序了,而ServiceManager提供辅助管理的功能,无论是Client还是Service进行通信前首先要和ServiceManager取得联系。而ServiceManager是一个守护进程,负责管理Server并向Client提供查询Server的功能。
在init.rc中servicemanager是作为服务启动的,而且是在zygote启动之前
service servicemanager /system/bin/servicemanager
class core
user system
group system
critical
onrestart restart zygote
onrestart restart media
onrestart restart surfaceflinger
onrestart restart drm
源码位置:frameworks/base/cmds/servicemanager/service_manager.c
int main(int argc, char** argv)
{
struct binder_state *bs;
void* svcmgr = BINDER_SERVICE_MANAGER; bs = binder_open(128*1024); binder_become_context_manager(bs); svcmgr_handle = svcmgr; binder_loop(bs, svcmgr_handler); return 0;
}
这里main函数主要有三个功能:
1)打开Binder设备文件
首先我们来看看这个struct binder_state结构体
struct binder_state
{
int fd; // 文件描述符,打开/dev/binder设备
void* mapped; // 把设备文件/dev/binder映射到进程空间的起始地址
unsigned mapsize; // 映射内存空间的大小
};
宏:#define BINDER_SERVICE_MANAGER ((void*)0)
表示ServiceManager对应的句柄为0,表面自己是服务器管理者。其他的Server进程句柄值都是大于0的。
struct binder_state* binder_open(unsigned mapsize)
{
struct binder_state* bs;
bs = malloc(sizeof(*bs));
bs->fd = open("/dev/binder", O_RDWR);
bs->mapsize = mapsize;
bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);
return bs;
}
这里主要就是打开Binder设备,映射128K的内存地址空间
2)告诉Binder驱动程序自己是Binder上下文管理者
int binder_become_context_manager(struct binder_state *bs)
{
return ioctl(bs->fd, BINDER_SET_CONTEXT_MGR, 0);
}
调用驱动程序设置这个进程为管理者BINDER_SET_CONTEXT_MGR
3)进入一个无线循环,充当server角色,等待Client的请求
void binder_loop(struct binder_state bs, binder_handler func)
{
struct binder_write_read bwr;
unsigned readbuf[32]; bwr.write_size = 0;
bwr.write_consumed = 0;
bwr.write_buffer = 0;
readbuf[0] = BC_ENTER_LOOPER; // 设置事件类型为LOOPER
// 调用ioctl函数,通知Binder设备servicemanager开始进入loop状态
binder_write(bs, readbuf, sizeof(unsigned)); for(;;) {
bwr.read_size = sizeof(readbuf);
bwr.read_consumed = 0;
bwr.read_buffer = (unsigned)readbuf;
// 进入Binder设备缓冲区,检查是否有IPC请求
ioctl(bs->fd, BINDER_WRITE_READ, &bwr);
// 对于请求调用binder_parse进行解析处理
binder_parse(bs, 0, readbuf, bwr.read_consumed, func);
}
} 这里我们看下struct binder_write_read这个结构体:
struct binder_write_read{
signed long write_size;
signed long write_consumed; // bytes consumed by driver
unsigned long write_buffer;
signed long read_size;
signed long read_consumed; // bytes consumed by driver
unsigned long read_buffer;
}; int binder_parse(struct binder_state *bs, struct binder_io *bio, uint32_t *ptr,
uint32_t size, binder_handler func)
{
uint32_t *end = ptr + (size / 4);
while(ptr < end) {
uint32_t cmd = *ptr++;
switch(cmd) {
......
case BR_TRANSACTOIN:{ // 收到请求进行处理
struct bindeer_txn *txn = (void*) ptr;
if(func) {
unsigned rdata[256/4];
struct binder_io msg;
struct binder_io reply;
bio_init(&reply, rdata, sizeof(rdata), 4);
bio_init_from_txn(&msg, txn);
ret = func(bs, txn, &msg, &reply);
binder_send_reply(bs, &reply, txn->data, res);
}
ptr += sizeof(*txn) / sizeof(uint32_t);
break;
}
case BR_REPLY: { // 回复的请求处理
struct binder_txn *txn = (void*)ptr;
if(bio) {
bio_init_from_txn(bio, txn);
bio = 0;
}else {
// to free buffer
}
ptr += sizeof(*txn) / sizeof(uint32_t);
r = 0;
break;
}
case BR_DEAD_BINDER: {
struct binder_death* death = (void*)*ptr++;
death->func(bs, death->ptr);
break;
}
...
}
}
return r;
}
/*这里binder_parse函数首先将binder读取过来的请求数据转化为bindeer_txn结构体,然后根据这个结构体
初始化binder_io msg,交给回调函数svcmgr_handler处理,同时返回一个binder_io reply,最后将
这个reply发送返回给客户端。*/
struc binder_io
{
char* data; // 指向read/write的数据
uint32_t *offs; // 偏移数组
uint32_t data_avail; // data中有效字节长
uint32_t offs_avail; // 偏移数组中有效字节长
char* data0; // data起始地址
uint32_t *offs0; // 偏移buffer的起始地址
uint32_t flags;
uint32_t unused;
};
最终调用的处理函数还是svcmgr_handler,终于要开始出来请求数据了: int svcmgr_handler(struct binder_state* bs, struct binder_txn *txn,
struct binder_io *msg, struct binder_io *reply)
{
struct svcinfo *si;
uint16_t *s;
unsigned len;
void* ptr;
uint32_t strict_policy; if(txn->target != svcmgr_handler)
return -1; // 首先判断这个消息的是不是发给自己的
strict_policy = bio_get_uint32(msg);
s = bio_get_string16(msg, &len);
switch(txn->code) {
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len); // 获取要查询的服务名字
ptr = do_find_service(bs, s, len); // 根据服务名字查找链表
bio_put_ref(reply, ptr);
return 0;
case SVC_MGR_ADD_SERVICE: // 添加服务
s = bio_get_string16(msg, &len);
ptr = bio_get_ref(msg);
do_add_service(bs, s, len, ptr, txn->sender_euid);
bio_put_uint32(reply, 0); // 告知添加成功
return 0;
....
}
return 0;
}
首先我们得看看Binder是怎么组织Binder传递消息的数据结构的,根据前面我们知道调用Binder驱动
的时候我们获得了一个void* ptr结构体,强制转化为binder_txn *txn,然后根据这个txn我们获得了
Binder的输入输出结构体binder_io *bio。最后我们不管是处理请求还是发送回复都是处理这个bio结构。
而我们的Binder通信的binder结构是由binder_object来组织的,指向binder_io结构里面data。
首先我们得看看Binder是怎么组织Binder传递消息的数据结构的,根据前面我们知道调用Binder驱动
的时候我们获得了一个void* ptr结构体,强制转化为binder_txn *txn,然后根据这个txn我们获得了
Binder的输入输出结构体binder_io *bio。最后我们不管是处理请求还是发送回复都是处理这个bio结构。
而我们的Binder通信的binder结构是由binder_object来组织的,指向binder_io结构里面data。
struct binder_object
{
uint32_t type;
uint32_t flags;
void* pointer;
void* cookie;
};
上面的binder_object结构体内容依次对应着我们代码中的:
bio_get_uint32(msg);
bio_get_string16(msg, &len);
bio_get_string16(msg, &len);
bio_get_ref(msg);
上面的binder_object结构体内容依次对应着我们代码中的:
bio_get_uint32(msg);
bio_get_string16(msg, &len);
bio_get_string16(msg, &len);
bio_get_ref(msg);
当客户端需要添加服务的时候:SVC_MGR_ADD_SERVICE
1)首先调用bio_get_string16()从binder_io中获得服务名字。
2)调用bio_get_ref()从binder_io中获得服务的binder实体struct binder_object
void* bio_get_ref(struct binder_io* bio)
{
struct binder_object* obj;
obj = _bio_get_obj(bio);// 这个函数最终调用的是 void* ptr = bio->data;
return obj->pointer;
}
3)调用do_add_service()将上面的Binder实体引用写到服务中,再通过名字加到全局链表中
int do_add_service(struct binder_state* bs, uint16_t *s, unsigned len, void* ptr, unsigned uid)
{
struct svcinfo *si; svc_can_register(uid, s); // 检查权限 si = find_svc(s, len);
// 根据名字查找链表,判断是否已经存在
si = malloc(sizeof(*si) + (len+1)*sizeof(uin16_t));
si->ptr = ptr; //指向上面的binder_object的pointer也就是Binder实体
memcpy(si->name, s, (len+1)*sizeof(uint16_t));
si->name[len] = '\0';
si->death.func = svcinfo_death;
si->death.ptr = si;
si->next = svclist;
svclist = si; binder_acquire(bs, ptr);
binder_link_to_death(bs, ptr, &si->death);
return 0;
}
当客户端需要查询服务的时候:
1)bio_get_string16() 获得服务名字
2)do_find_service() 遍历全局链表svclist,根据服务名字找到对应的服务并返回。
2)bio_put_ref(reply, ptr);这里reply就是需要返回给客户端的结构体,而ptr就是指向目标Binder实体。
void bio_put_ref(struct binder_io* bio, void* ptr)
{
struct binder_object *obj;
obj = bio_alloc(bio);
obj->flags = 0x7f | FLAT_BINDER_FLAG_ACCEPTS_FDS;
obj->type = BINDER_TYPE_HANDLE;
obj->pointer = ptr;
obj->cookie = 0;
}
回到binder_parse函数里面,执行:binder_send_reply()通知Binder驱动程序。
[置顶] Android开发之serviceManager分析的更多相关文章
- [置顶] Android开发之MediaPlayerService服务详解(一)
前面一节我们分析了Binder通信相关的两个重要类:ProcessState 和 IPCThreadState.ProcessState负责打开Binder 驱动,每个进程只有一个.而 IPCThre ...
- [置顶] Android开发之XML文件的解析
Android系统开发之XML文件的解析 我们知道Http在网络传输中的数据组织方式有三种分别为:XML方式.HTML方式.JSON方式.其中XML为可扩展标记语言,如下: <?xml vers ...
- [置顶] Android开发之ProcessState和IPCThreadState类分析
在Android中ProcessState是客户端和服务端公共的部分,作为Binder通信的基础,ProcessState是一个singleton类,每个 进程只有一个对象,这个对象负责打开Binde ...
- [置顶] Android开发之Thread类分析
在我们Linux系统中创建线程函数为:pthread_create(),在Android中我们为线程封装了一个类Thread,实际调用的还是pthread_create() 当我们想创建线程的时候,只 ...
- [置顶] android 心跳包的分析
android 心跳的分析 最近在做一个项目中用到了心跳包的机制,其实就是传统的长连接.或许有的人知道消息推送的机制,消息推送也是一种长连接 ,是将数据有服务器端推送到客户端这边从而改变传统的“拉”的 ...
- [置顶]Python开发之路
阅读目录 第一篇:python入门 第二篇:数据类型.字符编码.文件处理 第三篇:函数 第四篇:模块与包 第五篇:常用模块 第六篇:面向对象 第七篇:面向对象高级 第八篇:异常处理 第九篇:网络编 ...
- Android开发之Java集合类性能分析
对于Android开发者来说深入了解Java的集合类很有必要主要是从Collection和Map接口衍生出来的,目前主要提供了List.Set和 Map这三大类的集合,今天Android吧(ard8. ...
- Android开发之MdiaPlayer详解
Android开发之MdiaPlayer详解 MediaPlayer类可用于控制音频/视频文件或流的播放,我曾在<Android开发之基于Service的音乐播放器>一文中介绍过它的使用. ...
- Android开发之InstanceState详解
Android开发之InstanceState详解 本文介绍Android中关于Activity的两个神秘方法:onSaveInstanceState() 和 onRestoreInstanceS ...
随机推荐
- Windows 内核(WRK)编译
引子 WRK 是微软于 2006 年针对教育和学术界开放的 Windows 内核的部分源码, WRK(Windows Research Kernel)也就是 Windows 研究内核, 在 WRK 中 ...
- 【HDOJ】3275 Light
这就是个简单线段树+延迟标记.因为对bool使用了~而不是!,wa了一下午找不到原因. /* 3275 */ #include <iostream> #include <sstrea ...
- NOI2011道路修建
2435: [Noi2011]道路修建 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1974 Solved: 550[Submit][Status ...
- 【转】can't find referenced method 'android.app.RemoteInput[] getRemoteInputs()' in class android.app.Notification$Action
原文网址:http://stackoverflow.com/questions/25508735/cant-find-referenced-method-android-app-remoteinput ...
- c# 模拟http post 带cookie
下面的代码是自动向cnblogs中的小组发帖.........注意小组ID,主题ID,小组类型 首先采用firebug分析到发帖时的post地址以及参数,其中在headers中包含了cookies,把 ...
- ArcGIS Runtime for Android开发教程V2.0(8)基础篇-----地图事件
转自:http://blog.csdn.net/arcgis_mobile/article/details/8263283 ArcGIS Runtime sdk for Android为我们提供了丰富 ...
- HDU-4515 小Q系列故事——世界上最遥远的距离
小Q系列故事——世界上最遥远的距离 Time Limit: 500/200 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) ...
- C# 多线程是否结束可通过线程池可以判断
C# ManualResetEvent信号状态判断线程池是否结束 这是一段重要的代码,小猪两个小时的研究成果,记下来备查. using System; using System.Collection ...
- IIS中访问自己开发的Webservice site就自动停止,尝试重启IIS和重启服务器都不能解决。
今天在加班的时候发现一个奇怪的问题,IIS里面我们自己开发的Webservice site一访问就自动停止.尝试重启IIS和重启服务器都不能解决.后台windows events报错信息是The Mo ...
- leecode single numer
http://www.acmerblog.com/leetcode-single-number-ii-5394.html acm之家的讲解总是那么到位 public class Solution { ...