ServiceMananger是android中比较重要的一个进程,它是在init进程启动之后启动,从名字上就可以看出来它是用来管理系统中的service。比如:InputMethodService、ActivityManagerService等。在ServiceManager中有两个比较重要的方法:add_service、check_service。系统的service需要通过add_service把自己的信息注册到ServiceManager中,当需要使用时,通过check_service检查该service是否存在。

主函数

从它的主函数代码开始:

  1. int main(int argc, char **argv)
  2. {
  3. struct binder_state *bs;
  4. void *svcmgr = BINDER_SERVICE_MANAGER;
  5. bs = binder_open(128*1024);
  6. if (binder_become_context_manager(bs)) {
  7. LOGE("cannot become context manager (%s)\n", strerror(errno));
  8. return -1;
  9. }
  10. svcmgr_handle = svcmgr;
  11. binder_loop(bs, svcmgr_handler);
  12. return 0;
  13. }

从main函数中可以看出,它主要做了三件事情:

    1. 打开/dev/binder设备,并在内存中映射128K的空间。
    2. 通知Binder设备,把自己变成context_manager
    3. 进入循环,不停的去读Binder设备,看是否有对service的请求,如果有的话,就去调用svcmgr_handler函数回调处理请求。

服务注册

再来看看ServiceManager中是怎么样去注册服务的。先来看先,当有对service的请求时,调用的回调函数svcmgr_handler:

  1. int svcmgr_handler(struct binder_state *bs,
  2. struct binder_txn *txn,
  3. struct binder_io *msg,
  4. struct binder_io *reply)
  5. {
  6. struct svcinfo *si;
  7. uint16_t *s;
  8. unsigned len;
  9. void *ptr;
  10. uint32_t strict_policy;
  11. //  LOGI("target=%p code=%d pid=%d uid=%d\n",
  12. //  txn->target, txn->code, txn->sender_pid, txn->sender_euid);
  13. if (txn->target != svcmgr_handle)
  14. return -1;
  15. // Equivalent to Parcel::enforceInterface(), reading the RPC
  16. // header with the strict mode policy mask and the interface name.
  17. // Note that we ignore the strict_policy and don't propagate it
  18. // further (since we do no outbound RPCs anyway).
  19. strict_policy = bio_get_uint32(msg);
  20. s = bio_get_string16(msg, &len);
  21. if ((len != (sizeof(svcmgr_id) / 2)) ||
  22. memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
  23. fprintf(stderr,"invalid id %s\n", str8(s));
  24. return -1;
  25. }
  26. switch(txn->code) {
  27. case SVC_MGR_GET_SERVICE:
  28. case SVC_MGR_CHECK_SERVICE:
  29. s = bio_get_string16(msg, &len);
  30. ptr = do_find_service(bs, s, len);
  31. if (!ptr)
  32. break;
  33. bio_put_ref(reply, ptr);
  34. return 0;
  35. case SVC_MGR_ADD_SERVICE:
  36. s = bio_get_string16(msg, &len);
  37. ptr = bio_get_ref(msg);
  38. if (do_add_service(bs, s, len, ptr, txn->sender_euid))
  39. return -1;
  40. break;
  41. case SVC_MGR_LIST_SERVICES: {
  42. unsigned n = bio_get_uint32(msg);
  43. si = svclist;
  44. while ((n-- > 0) && si)
  45. si = si->next;
  46. if (si) {
  47. bio_put_string16(reply, si->name);
  48. return 0;
  49. }
  50. return -1;
  51. }
  52. default:
  53. LOGE("unknown code %d\n", txn->code);
  54. return -1;
  55. }
  56. bio_put_uint32(reply, 0);
  57. return 0;
  58. }

在该回调函数中会判断Service有什么需要,如果是请求注册service,那么久执行:

  1. case SVC_MGR_ADD_SERVICE:
  2. s = bio_get_string16(msg, &len);
  3. ptr = bio_get_ref(msg);
  4. if (do_add_service(bs, s, len, ptr, txn->sender_euid))
  5. return -1;
  6. break;

我们再来看看do_add_service中做了什么事情:

  1. int do_add_service(struct binder_state *bs,
  2. uint16_t *s, unsigned len,
  3. void *ptr, unsigned uid)
  4. {
  5. struct svcinfo *si;
  6. //    LOGI("add_service('%s',%p) uid=%d\n", str8(s), ptr, uid);
  7. if (!ptr || (len == 0) || (len > 127))
  8. return -1;
  9. if (!svc_can_register(uid, s)) {
  10. LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",
  11. str8(s), ptr, uid);
  12. return -1;
  13. }
  14. si = find_svc(s, len);
  15. if (si) {
  16. if (si->ptr) {
  17. LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n",
  18. str8(s), ptr, uid);
  19. return -1;
  20. }
  21. si->ptr = ptr;
  22. } else {
  23. si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
  24. if (!si) {
  25. LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",
  26. str8(s), ptr, uid);
  27. return -1;
  28. }
  29. si->ptr = ptr;
  30. si->len = len;
  31. memcpy(si->name, s, (len + 1) * sizeof(uint16_t));
  32. si->name[len] = '\0';
  33. si->death.func = svcinfo_death;
  34. si->death.ptr = si;
  35. si->next = svclist;
  36. svclist = si;
  37. }
  38. binder_acquire(bs, ptr);
  39. binder_link_to_death(bs, ptr, &si->death);
  40. return 0;
  41. }

在该函数中,首先会去检查是否有权限注册service,如果没有权限就直接返回,不能注册。

  1. if (!svc_can_register(uid, s)) {
  2. LOGE("add_service('%s',%p) uid=%d - PERMISSION DENIED\n",
  3. str8(s), ptr, uid);
  4. return -1;
  5. }

然后会去检查该service是否已经注册过了,如果已经注册过,那么就不能再注册了:

  1. si = find_svc(s, len);
  2. if (si) {
  3. if (si->ptr) {
  4. LOGE("add_service('%s',%p) uid=%d - ALREADY REGISTERED\n",
  5. str8(s), ptr, uid);
  6. return -1;
  7. }
  8. si->ptr = ptr;
  9. }

再判断内存是否足够:

  1. si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
  2. if (!si) {
  3. LOGE("add_service('%s',%p) uid=%d - OUT OF MEMORY\n",
  4. str8(s), ptr, uid);
  5. return -1;
  6. }

如果都没什么问题,会注册该service,加入到svcList中来。注意,在ServiceManager中维护service信息的地方就是svclist。里面存了service的name和handler。

服务获取

通过以上几个步骤,service就算注册成功了。那么当要获得该service的时候又是怎么去处理的。还是来看下回调函数中的判断:

  1. case SVC_MGR_CHECK_SERVICE:
  2. s = bio_get_string16(msg, &len);
  3. ptr = do_find_service(bs, s, len);
  4. if (!ptr)
  5. break;
  6. bio_put_ref(reply, ptr);
  7. return 0;

如果是获取service,那么执行SVC_MGR_CHECK_SERVICE,并把返回的数据写入reply,返回给客户端。

do_find_service函数中主要执行service的查找。

  1. void *do_find_service(struct binder_state *bs, uint16_t *s, unsigned len)
  2. {
  3. struct svcinfo *si;
  4. si = find_svc(s, len);
  5. //    LOGI("check_service('%s') ptr = %p\n", str8(s), si ? si->ptr : 0);
  6. if (si && si->ptr) {
  7. return si->ptr;
  8. } else {
  9. return 0;
  10. }
  11. }

这样在ServiceManager中就完成了服务的注册和查找。来看下ServiceManager的功能图:

Android 之 ServiceManager与服务管理的更多相关文章

  1. i.mx6 Android5.1.1 servicemanager本地服务

    接在之前的 i.mx6 Android5.1.1 初始化流程之init进程 i.mx6 Android5.1.1 初始化流程之init.rc解析 servicemanager是由init创建的本地服务 ...

  2. [译]:Xamarin.Android平台功能——位置服务

    返回索引目录 原文链接:Location Services. 译文链接:Xamarin.Android平台功能--位置服务 本部分介绍位置服务以及与如何使用位置提供商服务 Location Servi ...

  3. PC管理端与评委云打分配合步骤及疑难问题汇编,即如何使用PC管理端的云服务管理功能

    一.前期环境及数据准备 A.PC管理端主要流程 1.进入菜单 编辑/选项/服务器 界面,如下图所示,采用我官方所提供的云服务,不采用自己假设的AppWeb服务. 切记:AppWeb服务和云服务只能二选 ...

  4. Android开发-API指南-服务

    Service 英文原文:http://developer.android.com/guide/components/services.html 采集(更新)日期:2014-12-23 原博客:htt ...

  5. [置顶] Android开发之MediaPlayerService服务详解(一)

    前面一节我们分析了Binder通信相关的两个重要类:ProcessState 和 IPCThreadState.ProcessState负责打开Binder 驱动,每个进程只有一个.而 IPCThre ...

  6. Android中使用HTTP服务

    在Android中,除了使用java.net包下的API访问HTTP服务之外,我们还可以换一种途径去完成工作.Android SDK附带了Apache的HttpClient API.Apache Ht ...

  7. wemall app商城源码中基于JAVA的Android异步加载图片管理器代码

    wemall doraemon是Android客户端程序,服务端采用wemall微信商城,不对原商城做任何修改,只需要在原商城目录下上传接口文件即可完成服务端的配置,客户端可随意定制修改.本文分享其中 ...

  8. [Android][Framework]裁剪SystemServer服务以及关闭SystemFeature

    本文链接 http://wossoneri.github.io/2018/08/30/[Android][Framework]crop-SystemServer-and-SystemFeature/ ...

  9. Android开发--用户定位服务--UserLocation

    Android开发--用户定位服务--UserLocation 2013-01-28 08:32:26     我来说两句      作者:BruceZhang 收藏    我要投稿 [java] & ...

随机推荐

  1. iOS:UIWebView scrollView 的分页滑动问题

    最近在弄一个native webview+html的项目,感觉这种尝试还是挺不错的,特被是适合内容类app.如杂志.电子书等.其实native搭的就是一个框架,主体还是在html的内容上,所以花在ht ...

  2. 如何使用 AngularJS 的 ngShow 和 ngHide

    今天我们来看看怎样使用Angular的ngShow 和ngHide 指令来完成它们听起来应该完成的,显示和隐藏! 它们应该做的事 ngShow 和ngHide 允许我们显示或隐藏不同的元素.这有助于创 ...

  3. iOS传值之通知传值(三)

    输入所要发送的信息 ,同时将label的值通过button方法调用传递, - (IBAction)buttonClick:(id)sender { //添加 字典,将label的值通过key值设置传递 ...

  4. 在idea的maven项目使用el或jstl表达式

    必须加上这句: <%@ page isELIgnored="false" %> 否则无法解析el或jstl表达式 <%@ taglib prefix=" ...

  5. Struts2中的验证框架

    通过注解的方式,可以让方法不用验证 @SkipValidation public String toRegView() { System.out.println("toRegView&quo ...

  6. 创建zend framework 项目要注意的

    1.必须要设置变量环境 我的电脑右击-属性-高级-环境变量 则在环境变量中添加 变量名:PATH 环境值:D:\phpserver\php5.4;D:\ZendFramework\bin 把php.e ...

  7. 深入解析FileInputStream和FileOutputStream

    http://swiftlet.net/archives/1363 FileInputStream和FileOutputStream类属于字节类,可以操作任意类型的文件.在数据流的处理过程中,有两种情 ...

  8. 解析GenericOptionsParser

    hadoop源代码分析(4)-org.apache.hadoop.util包-GenericOptionsParser类[原创]   一  准备 hadoop版本:1.0.3,GenericOptio ...

  9. JavaScript的异步机制

    我们经常说JS是单线程的,比如node.js研讨会上大家都说JS的特色之一是单线程的,这样使JS更简单明了,可是大家真的理解所谓JS的单线程机制吗?单线程时,基于事件的异步机制又该当如何 1 先看下两 ...

  10. C1 FlexGrid控件 Editor 冲突问题

    当给C1FlexGrid控件加入 Checkbox后,添加新行时对新行的Editor 赋新控件时,会冲突如下图:       下面我们借助BeforeRowColChange 事件来解决这个问题: 我 ...