软件编程
位置:首页>> 软件编程>> Android编程>> Android 10 启动之servicemanager源码解析

Android 10 启动之servicemanager源码解析

作者:格子里的梦  发布时间:2023-05-16 15:04:53 

标签:Android10,启动,servicemanager

上一篇文章:

Android 10 启动分析之Init篇 (一)

在前文提到,init进程会在在Trigger 为init的Action中,启动servicemanager服务,这篇文章我们就来具体分析一下servicemanager服务,它到底做了哪些事情。

servicemanager服务的源码位于/frameworks/native/cmds/servicemanager/service_manager.c,我们将从这个类的入口开始看起。

int main(int argc, char** argv)
{
   struct binder_state *bs;
   union selinux_callback cb;
   char *driver;
   if (argc > 1) {
       driver = argv[1];
   } else {
       //启动时默认无参数,走这个分支
       driver = "/dev/binder";
   }
   //打开binder驱动,并设置mmap的内存大小为128k
   bs = binder_open(driver, 128*1024);
   ...
  if (binder_become_context_manager(bs)) {
       ALOGE("cannot become context manager (%s)\n", strerror(errno));
       return -1;
   }
   cb.func_audit = audit_callback;
   selinux_set_callback(SELINUX_CB_AUDIT, cb);
#ifdef VENDORSERVICEMANAGER
   cb.func_log = selinux_vendor_log_callback;
#else
   cb.func_log = selinux_log_callback;
#endif
   selinux_set_callback(SELINUX_CB_LOG, cb);
#ifdef VENDORSERVICEMANAGER
   sehandle = selinux_android_vendor_service_context_handle();
#else
   sehandle = selinux_android_service_context_handle();
#endif
   selinux_status_open(true);
   if (sehandle == NULL) {
       ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
       abort();
   }
   if (getcon(&service_manager_context) != 0) {
       ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
       abort();
   }
    /* binder_loop已封装如下步骤:
   while (1)
   {
       /* read data */
       /* parse data, and process */
       /* reply */
   }
   */
   binder_loop(bs, svcmgr_handler);
   return 0;
}

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

  • 打开/dev/binder设备,并在内存中映射128K的空间。

  • 通知Binder设备,把自己变成context_manager,其他用户进程都通过0号句柄访问ServiceManager。

  • 进入循环,不停的去读Binder设备,看是否有对service的请求,如果有的话,就去调用svcmgr_handler函数回调处理请求。

我们再来看看svcmgr_handler函数的实现:

int svcmgr_handler(struct binder_state *bs,
                 struct binder_transaction_data_secctx *txn_secctx,
                 struct binder_io *msg,
                 struct binder_io *reply)
{
  struct svcinfo *si;
  uint16_t *s;
  size_t len;
  uint32_t handle;
  uint32_t strict_policy;
  int allow_isolated;
  uint32_t dumpsys_priority;
  struct binder_transaction_data *txn = &txn_secctx->transaction_data;
  if (txn->target.ptr != BINDER_SERVICE_MANAGER)
      return -1;
  if (txn->code == PING_TRANSACTION)
      return 0;
  ...
  switch(txn->code) {
  case SVC_MGR_GET_SERVICE:
  case SVC_MGR_CHECK_SERVICE:
      s = bio_get_string16(msg, &len);
      if (s == NULL) {
          return -1;
      }
      handle = do_find_service(s, len, txn->sender_euid, txn->sender_pid,
                               (const char*) txn_secctx->secctx);
      if (!handle)
          break;
      bio_put_ref(reply, handle);
      return 0;
  case SVC_MGR_ADD_SERVICE:
      s = bio_get_string16(msg, &len);
      if (s == NULL) {
          return -1;
      }
      handle = bio_get_ref(msg);
      allow_isolated = bio_get_uint32(msg) ? 1 : 0;
      dumpsys_priority = bio_get_uint32(msg);
      if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
                         txn->sender_pid, (const char*) txn_secctx->secctx))
          return -1;
      break;
  case SVC_MGR_LIST_SERVICES: {
      uint32_t n = bio_get_uint32(msg);
      uint32_t req_dumpsys_priority = bio_get_uint32(msg);
      if (!svc_can_list(txn->sender_pid, (const char*) txn_secctx->secctx, txn->sender_euid)) {
          ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
                  txn->sender_euid);
          return -1;
      }
      si = svclist;
      // walk through the list of services n times skipping services that
      // do not support the requested priority
      while (si) {
          if (si->dumpsys_priority & req_dumpsys_priority) {
              if (n == 0) break;
              n--;
          }
          si = si->next;
      }
      if (si) {
          bio_put_string16(reply, si->name);
          return 0;
      }
      return -1;
  }
  default:
      ALOGE("unknown code %d\n", txn->code);
      return -1;
  }
  bio_put_uint32(reply, 0);
  return 0;
}

我们先来认识一下binder的数据传输载体binder_transaction_data:

struct binder_transaction_data {
 union {
 /* 当binder_transaction_data是由用户空间的进程发送给Binder驱动时,
handle是该事务的发送目标在Binder驱动中的信息,即该事务会交给handle来处理;
 handle的值是目标在Binder驱动中的Binder引用。*/
   __u32 handle;
   /* 当binder_transaction_data是有Binder驱动反馈给用户空间进程时,
  ptr是该事务的发送目标在用户空间中的信息,即该事务会交给ptr对应的服务来处理;
  ptr是处理该事务的服务的服务在用户空间的本地Binder对象。*/
   binder_uintptr_t ptr;
 } target;  // 该事务的目标对象(即,该事务数据包是给该target来处理的)
 // 只有当事务是由Binder驱动传递给用户空间时,cookie才有意思,它的值是处理该事务的ServerC++层的本地Binder对象
 binder_uintptr_t cookie;
 // 事务编码。如果是请求,则以BC_开头;如果是回复,则以BR_开头。
 __u32 code;
 /* General information about the transaction. */
 __u32 flags;
 //表示事务发起者的pid和uid。
 pid_t sender_pid;
 uid_t sender_euid;
 // 数据大小
 binder_size_t data_size;
 //数据偏移量
 binder_size_t offsets_size;
 //data是一个共用体,当通讯数据很小的时,可以直接使用buf[8]来保存数据。当够大时,只能用指针buffer来描述一个申请的数据缓冲区。
 union {
   struct {
      /* transaction data */
     binder_uintptr_t buffer;
     binder_uintptr_t offsets;
   } ptr;
   __u8 buf[8];
 } data;
};

可以看到,svcmgr_handler函数中对binder data的事务编码进行了判断,并分别对SVC_MGR_GET_SERVICE(SVC_MGR_CHECK_SERVICE)SVC_MGR_ADD_SERVICESVC_MGR_LIST_SERVICES三种类型的事务编码做了业务处理。

获取服务

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;

do_find_service函数中主要执行service的查找,并把找到的服务句柄写入reply,返回给客户端。

uint32_t do_find_service(const uint16_t *s, size_t len, uid_t uid, pid_t spid, const char* sid)
{
   struct svcinfo *si = find_svc(s, len);
   ...
   return si->handle;
}

我们继续看find_svc函数:

struct svcinfo *find_svc(const uint16_t *s16, size_t len)
{
   struct svcinfo *si;
   for (si = svclist; si; si = si->next) {
       if ((len == si->len) &&
           !memcmp(s16, si->name, len * sizeof(uint16_t))) {
           return si;
       }
   }
   return NULL;
}

svclist 是一个单向链表,储存了所有向servicemanager注册的服务信息。find_svc遍历svclist链表,通过服务名称作为索引条件,最终找到符合条件的服务。

注册服务

case SVC_MGR_ADD_SERVICE:
       s = bio_get_string16(msg, &len);
       if (s == NULL) {
           return -1;
       }
       handle = bio_get_ref(msg);
       allow_isolated = bio_get_uint32(msg) ? 1 : 0;
       dumpsys_priority = bio_get_uint32(msg);
       if (do_add_service(bs, s, len, handle, txn->sender_euid, allow_isolated, dumpsys_priority,
       txn->sender_pid, (const char*) txn_secctx->secctx))
           return -1;

我们继续看do_add_service函数中做了哪些事情。

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

if (!svc_can_register(s, len, spid, sid, uid)) {
       ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
            str8(s, len), handle, uid);
       return -1;
   }

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

si = find_svc(s, len);
   if (si) {
       if (si->handle) {
           ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
                str8(s, len), handle, uid);
           svcinfo_death(bs, si);
       }
       si->handle = handle;
   }

再判断内存是否足够。

si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
       if (!si) {
           ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
                str8(s, len), handle, uid);
           return -1;
       }

如果都没什么问题,会注册该service,并加入到svcList链表中。

综上所述,servicemanager主要负责查询和注册其他的系统服务,是系统服务的管理者。

文章的最后,留给大家一个问题进行思考:

为什么Android需要设计servicemanager做中转来添加和获取系统服务,而不直接让客户端去获取服务端句柄?

来源:https://juejin.cn/post/6999537375768477727

0
投稿

猜你喜欢

手机版 软件编程 asp之家 www.aspxhome.com