文档章节

Android 之 ServiceManager与服务管理

t
 taoanran
发布于 2012/08/11 18:00
字数 1069
阅读 323
收藏 4

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

    主函数(anrdroid4.0/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);
        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函数中可以看出,它主要做了三件事情:

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

    再来看看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的功能图:

本文转载自:http://blog.csdn.net/xieqibao/article/details/6585143

t
粉丝 7
博文 64
码字总数 7186
作品 0
南京
私信 提问
加载中

评论(0)

详解 Android 系统启动过程

Android的启动过程可以分为两个阶段,第一阶段是Linux的启动,第二阶段才是Android的启动,下面我们分别来了解一下具体的过程。 首先是Linux启动,这一部分我想就可以略过了,无非是Linux的B...

鉴客
2011/09/15
1.2W
0
在ServiceManager中加入自定义的服务

当我们要使用android的系统服务时,一般都是使用Context.getSystemService方法。例如我们要获取AudioManager,我们可以: AudioManager am = (AudioManager) getSystemService(Context.AUDI...

cwr
2015/02/23
8K
4
听说你Binder机制学的不错,来面试下这几个问题(一)

Binder承担了绝大部分Android进程通信的职责,可以看做是Android的血管系统,负责不同服务模块进程间的通信。在对Binder的理解上,可大可小,日常APP开发并不怎么涉及Binder通信知识,最多就...

技术小能手
2018/07/20
0
0
Android10.0 Binder通信原理(三)-ServiceManager篇

摘要:本节主要来讲解Android10.0 Binder中守护进程ServiceManager是如何启动、注册、获取服务 [Android取经之路] 的源码都基于Android-Q(10.0) 进行分析 [Android取经之路] 系列文章: 《...

IngresGe
03/31
0
0
腾讯面试官:Binder的系统服务是如何获取的?

本文首发于微信公众号「后厂村码农」 关联系列 Android AOSP基础系列 Android系统启动系列 应用进程启动系列 Android深入四大组件系列 Android深入理解Context系列 Android深入理解JNI系列 ...

刘望舒
2019/11/28
0
0

没有更多内容

加载失败,请刷新页面

加载更多

如何让图卷积网络变深?腾讯AI Lab联合清华提出DropEdge

  机器之心发布   机器之心编辑部      近年来,图神经网络的研究异常火爆,被各大顶会录取的文章数量爆炸式增长。然而,目前大部分图卷积网络,尤其是面向节点分类的网络,都是浅层...

osc_v1ao43h5
9分钟前
16
0
疫情夹缝中的顶会ECCV:程序主席一度失联,投稿热情不减

  机器之心报道   参与:蛋酱、张倩      程序主席都病了,今年的 ECCV 要怎么办?   据外媒报道,英国首相鲍里斯·约翰逊因新冠病情恶化转入 ICU,成为受新冠严重影响的另一位政要...

osc_hzf6peqc
10分钟前
13
0
李飞飞团队最新研究 :「四步」AI方案助老人抵抗新冠肺炎

      自2018年回归学术界后,李飞飞教授便很少对外露面,近日在一次斯坦福的线上会议,让我们有机会了解她与团队的最新研究——《AI-ASSISTED IN-HOME ELDERLY CARE AMID COVID-19 PAND...

osc_cyo5y1ey
12分钟前
5
0
人脸识别再曝安全漏洞:清华创业团队推出全球首个AI模型杀毒软件

  机器之心报道   参与:泽南   瑞莱智慧刚刚发布的首个 AI 安全平台,发现了迄今为止最为「重大」的人脸识别安全漏洞。   4 月 7 日,来自清华的 RealAI(瑞莱智慧)发布了 RealSa...

osc_2uc536xl
13分钟前
6
0
BigDecimal除法后保留两位小数

BigDecimal cnt;BigDecimal totalCnt = new BigDecimal(total); cnt = new BigDecimal(po.getId() * 100);Double d = cnt.divide(totalCnt, 2, BigDecimal.ROUND_HALF_UP).doubleValue()......

zxx901221
13分钟前
17
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部