Android 之 ServiceManager与服务管理
ServiceMananger是android中比较重要的一个进程,它是在init进程启动之后启动,从名字上就可以看出来它是用来管理系统中的service。比如:InputMethodService、ActivityManagerService等。在ServiceManager中有两个比较重要的方法:add_service、check_service。系统的service需要通过add_service把自己的信息注册到ServiceManager中,当需要使用时,通过check_service检查该service是否存在。
主函数
从它的主函数代码开始:
- int main(int argc, char **argv)
- {
- struct binder_state *bs;
- void *svcmgr = BINDER_SERVICE_MANAGER;
- bs = binder_open(128*1024);
- if (binder_become_context_manager(bs)) {
- LOGE("cannot become context manager (%s)\n", strerror(errno));
- return -1;
- }
- svcmgr_handle = svcmgr;
- binder_loop(bs, svcmgr_handler);
- return 0;
- }
从main函数中可以看出,它主要做了三件事情:
- 打开/dev/binder设备,并在内存中映射128K的空间。
- 通知Binder设备,把自己变成context_manager
- 进入循环,不停的去读Binder设备,看是否有对service的请求,如果有的话,就去调用svcmgr_handler函数回调处理请求。
服务注册
再来看看ServiceManager中是怎么样去注册服务的。先来看先,当有对service的请求时,调用的回调函数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;
- // LOGI("target=%p code=%d pid=%d uid=%d\n",
- // txn->target, txn->code, txn->sender_pid, txn->sender_euid);
- if (txn->target != svcmgr_handle)
- return -1;
- // Equivalent to Parcel::enforceInterface(), reading the RPC
- // header with the strict mode policy mask and the interface name.
- // Note that we ignore the strict_policy and don't propagate it
- // further (since we do no outbound RPCs anyway).
- strict_policy = bio_get_uint32(msg);
- s = bio_get_string16(msg, &len);
- if ((len != (sizeof(svcmgr_id) / 2)) ||
- memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
- fprintf(stderr,"invalid id %s\n", str8(s));
- return -1;
- }
- 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);
- if (!ptr)
- break;
- bio_put_ref(reply, ptr);
- return 0;
- case SVC_MGR_ADD_SERVICE:
- s = bio_get_string16(msg, &len);
- ptr = bio_get_ref(msg);
- if (do_add_service(bs, s, len, ptr, txn->sender_euid))
- return -1;
- break;
- case SVC_MGR_LIST_SERVICES: {
- unsigned n = bio_get_uint32(msg);
- si = svclist;
- while ((n-- > 0) && si)
- si = si->next;
- if (si) {
- bio_put_string16(reply, si->name);
- return 0;
- }
- return -1;
- }
- default:
- LOGE("unknown code %d\n", txn->code);
- return -1;
- }
- bio_put_uint32(reply, 0);
- return 0;
- }
在该回调函数中会判断Service有什么需要,如果是请求注册service,那么久执行:
- case SVC_MGR_ADD_SERVICE:
- s = bio_get_string16(msg, &len);
- ptr = bio_get_ref(msg);
- if (do_add_service(bs, s, len, ptr, txn->sender_euid))
- return -1;
- break;
我们再来看看do_add_service中做了什么事情:
- int do_add_service(struct binder_state *bs,
- uint16_t *s, unsigned len,
- void *ptr, unsigned uid)
- {
- struct svcinfo *si;
- // LOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid);
- if (!ptr || (len == 0) || (len > 127))
- return -1;
- if (!svc_can_register(uid, s)) {
- LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",
- str8(s), ptr, uid);
- return -1;
- }
- si = find_svc(s, len);
- if (si) {
- if (si->ptr) {
- LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n",
- str8(s), ptr, uid);
- return -1;
- }
- si->ptr = ptr;
- } else {
- si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
- if (!si) {
- LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",
- str8(s), ptr, uid);
- return -1;
- }
- si->ptr = ptr;
- si->len = len;
- 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;
- }
在该函数中,首先会去检查是否有权限注册service,如果没有权限就直接返回,不能注册。
- if (!svc_can_register(uid, s)) {
- LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",
- str8(s), ptr, uid);
- return -1;
- }
然后会去检查该service是否已经注册过了,如果已经注册过,那么就不能再注册了:
- si = find_svc(s, len);
- if (si) {
- if (si->ptr) {
- LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n",
- str8(s), ptr, uid);
- return -1;
- }
- si->ptr = ptr;
- }
再判断内存是否足够:
- si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
- if (!si) {
- LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",
- str8(s), ptr, uid);
- return -1;
- }
如果都没什么问题,会注册该service,加入到svcList中来。注意,在ServiceManager中维护service信息的地方就是svclist。里面存了service的name和handler。
服务获取
通过以上几个步骤,service就算注册成功了。那么当要获得该service的时候又是怎么去处理的。还是来看下回调函数中的判断:
- case SVC_MGR_CHECK_SERVICE:
- s = bio_get_string16(msg, &len);
- ptr = do_find_service(bs, s, len);
- if (!ptr)
- break;
- bio_put_ref(reply, ptr);
- return 0;
如果是获取service,那么执行SVC_MGR_CHECK_SERVICE,并把返回的数据写入reply,返回给客户端。
do_find_service函数中主要执行service的查找。
- void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)
- {
- struct svcinfo *si;
- si = find_svc(s, len);
- // LOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
- if (si && si->ptr) {
- return si->ptr;
- } else {
- return 0;
- }
- }
这样在ServiceManager中就完成了服务的注册和查找。来看下ServiceManager的功能图:
Android 之 ServiceManager与服务管理的更多相关文章
- i.mx6 Android5.1.1 servicemanager本地服务
接在之前的 i.mx6 Android5.1.1 初始化流程之init进程 i.mx6 Android5.1.1 初始化流程之init.rc解析 servicemanager是由init创建的本地服务 ...
- [译]:Xamarin.Android平台功能——位置服务
返回索引目录 原文链接:Location Services. 译文链接:Xamarin.Android平台功能--位置服务 本部分介绍位置服务以及与如何使用位置提供商服务 Location Servi ...
- PC管理端与评委云打分配合步骤及疑难问题汇编,即如何使用PC管理端的云服务管理功能
一.前期环境及数据准备 A.PC管理端主要流程 1.进入菜单 编辑/选项/服务器 界面,如下图所示,采用我官方所提供的云服务,不采用自己假设的AppWeb服务. 切记:AppWeb服务和云服务只能二选 ...
- Android开发-API指南-服务
Service 英文原文:http://developer.android.com/guide/components/services.html 采集(更新)日期:2014-12-23 原博客:htt ...
- [置顶] Android开发之MediaPlayerService服务详解(一)
前面一节我们分析了Binder通信相关的两个重要类:ProcessState 和 IPCThreadState.ProcessState负责打开Binder 驱动,每个进程只有一个.而 IPCThre ...
- Android中使用HTTP服务
在Android中,除了使用java.net包下的API访问HTTP服务之外,我们还可以换一种途径去完成工作.Android SDK附带了Apache的HttpClient API.Apache Ht ...
- wemall app商城源码中基于JAVA的Android异步加载图片管理器代码
wemall doraemon是Android客户端程序,服务端采用wemall微信商城,不对原商城做任何修改,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可随意定制修改.本文分享其中 ...
- [Android][Framework]裁剪SystemServer服务以及关闭SystemFeature
本文链接 http://wossoneri.github.io/2018/08/30/[Android][Framework]crop-SystemServer-and-SystemFeature/ ...
- Android开发--用户定位服务--UserLocation
Android开发--用户定位服务--UserLocation 2013-01-28 08:32:26 我来说两句 作者:BruceZhang 收藏 我要投稿 [java] & ...
随机推荐
- Java&&As3.0 中的final 关键字
Java和AS3.0关键字final有“这是无法改变的”或者“终态的”含义,它可以修饰非抽象类.非抽象类成员方法和变量.你可能出于两种理解而需要阻止改变:设计或效率. 可以修饰的对象: fin ...
- Docker私有仓库Registry 搭建
1. 关于Registry 官方的Docker hub是一个用于管理公共镜像的好地方,我们可以在上面找到我们想要的镜像,也可以把我们自己的镜像推送上去.但是,有时候,我们的使用场景需要我们拥有一个私有 ...
- Linux中切换用户变成-bash4.1-$的解决方法【转】
转自 Linux中切换用户变成-bash4.1-$的解决方法 - xia_xia的博客 - 博客频道 - CSDN.NEThttp://blog.csdn.net/xia_xia0919/articl ...
- 使用composer安装laravel
跟具官方文档说:Laravel utilizes Composer to manage its dependencies. So, before using Laravel, you will nee ...
- J2EE判断重复的数据
import java.util.ArrayList; import java.util.List; import org.junit.Test; /** * 判断重复的数据 * @author Ya ...
- vs2010在进行数据架构比较时报'text lines should not be null'错误
通过VS2010进行服务器数据库和本地数据库比较架构(都是sql server 2008 R2)时,弹出“text lines should be not null”错误,如下图: 解决方法:在Vis ...
- 扩展方法之ToDictionary()
Person类: public class Person { public int Id { set; get; } public string WorkNo { set; get; } public ...
- GDT、GDTR、LDT、LDTR的理解
GDT是全局描述附表,主要存放操作系统和各任务公用的描述符,如公用的数据和代码段描述符.各任务的TSS描述符和LDT描述符.(TSS是任务状态段,存放各个任务私有运行状态信息描述符)LDT是局部描述符 ...
- sql trim()函数去掉两头空格
1.sql trim()函数去掉两头空格 sql语法中没有直接去除两头空格的函数,但有ltrim()去除左空格rtrim()去除右空格. 合起来用就是sql的trim()函数,即select ltri ...
- Illegal resource reference: @*android resources are private and not always present
0:前言 在android开发中,当使用别人的代码的时候,在style.xml中有此种错误 1:解决方案 删除*星号