背景:

在Android开发中,经常会用到ServiceManager.addService(name, service);添加系统服务
也许你会很迷惑,在程序运行时,部分service name能成功添加,而部分service name会抛出如下异常:

Tag: ServiceManagerMessage: add_service('xxx',xx) uid=xxxx - PERMISSION DENIED

这是Android SELinux 的policy配置引起的,在读了部分SELinux的源码之后就很容易理解这个异常了
接下来我会先给出解决办法,然后再进行分析。

解决办法:

针对不同得设备,可以在device或vendor目录下的BoardConfig.mk中使用BOARD_SEPOLICY_DIRS变量指定配置文件的目录;
新的service_type定义在service.te中,对应该service_type的service name定义在service_contexts中。

注: service_manager 不能add default_android_service类型的service

例如:
针对samsung tuna设备:device/samsung/tuna/BoardConfig.mk

BOARD_SEPOLICY_DIRS += device/samsung/tuna/sepolicy

device/samsung/tuna/sepolicy/service.te

type yyy,           service_manager_type

device/samsung/tuna/sepolicy/service_contexts

xxx             u:object_r:yyy:s0

这样再使用ServiceManager.addService(“xxx”, this);添加系统服务就不会抛异常了。

分析:

service_manager初始化以及ServiceManager.addService(“xxx”, this);方法调用流程:
service_manager.c

static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name){    ...    if (selabel_lookup(sehandle, &tctx, name, 0) != 0) {    //libselinux/src/label.c : selabel_lookup()                                                            //service name 会在该函数中进行匹配        ALOGE("SELinux: No match for %s in service_contexts.\n", name);        return false;    }    ...}static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid){    const char *perm = "add";    return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;}int do_add_service(struct binder_state *bs,                   const uint16_t *s, size_t len,                   uint32_t handle, uid_t uid, int allow_isolated,                   pid_t spid){    ...    if (!svc_can_register(s, len, spid, uid)) { //若svc_can_registe()返回false,则抛出上述异常        ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",             str8(s, len), handle, uid);        return -1;    }    ...}int svcmgr_handler(struct binder_state *bs,                   struct binder_transaction_data *txn,                   struct binder_io *msg,                   struct binder_io *reply){    ...    switch(txn->code) {    case SVC_MGR_GET_SERVICE:    case SVC_MGR_CHECK_SERVICE:        ...        handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);        ...        return 0;    case SVC_MGR_ADD_SERVICE:        ...        if (do_add_service(bs, s, len, handle, txn->sender_euid,            allow_isolated, txn->sender_pid))   //ServiceManager.addService("xxx", this);最终调用do_add_service函数            return -1;        break;    case SVC_MGR_LIST_SERVICES: {        uint32_t n = bio_get_uint32(msg);        if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {            ALOGE("list_service() uid=%d - PERMISSION DENIED\n",                    txn->sender_euid);            return -1;        }        si = svclist;        while ((n-- > 0) && si)            si = si->next;        if (si) {            bio_put_string16(reply, si->name);            return 0;        }        return -1;    }    default:        ...    }    bio_put_uint32(reply, 0);    return 0;}int main(int argc, char **argv){    struct binder_state *bs;    bs = binder_open(128*1024); //binder.c : binder_open(size_t mapsize)                                //bs->fd = open("/dev/binder", O_RDWR);                                //bs->mapsize = mapsize;                                //bs->mapped = mmap(NULL, mapsize, PROT_READ, MAP_PRIVATE, bs->fd, 0);    ...    sehandle = selinux_android_service_context_handle();    //libselinux/src/android.c  :   selinux_android_service_context_handle(void)    ...    union selinux_callback cb;    cb.func_audit = audit_callback;    selinux_set_callback(SELINUX_CB_AUDIT, cb);    ...    binder_loop(bs, svcmgr_handler);    //binder.c : binder_loop(struct binder_state *bs, binder_handler func)                                        //无限循环读取解析处理消息回调svcmgr_handler函数    return 0;}

libselinux/src/label_internal.h

struct selabel_handle {    /* arguments that were passed to selabel_open */    unsigned int backend;    int validating;    /* labeling operations */    struct selabel_lookup_rec *(*func_lookup) (struct selabel_handle *h,                           const char *key, int type);    void (*func_close) (struct selabel_handle *h);    void (*func_stats) (struct selabel_handle *h);    bool (*func_partial_match) (struct selabel_handle *h, const char *key);    struct selabel_lookup_rec *(*func_lookup_best_match) (struct selabel_handle *h,                             const char *key,                             const char **aliases,                             int type);    /* supports backend-specific state information */    void *data;    /* substitution support */    struct selabel_sub *subs;};

libselinux/src/android.c

static const struct selinux_opt seopts_service[] = {    { SELABEL_OPT_PATH, "/service_contexts" },  //service_contexts文件中配置service name    { SELABEL_OPT_PATH, "/data/security/current/service_contexts" },    { 0, NULL }};struct selabel_handle* selinux_android_service_context_handle(void){    struct selabel_handle* sehandle;    set_policy_index();    sehandle = selabel_open(SELABEL_CTX_ANDROID_PROP/* 4 */,            &seopts_service[policy_index/* 0 /service_contexts */], 1);    ...    return sehandle;}

libselinux/src/label.c

static selabel_initfunc initfuncs[] = {    &selabel_file_init,    &selabel_media_init,    &selabel_x_init,    &selabel_db_init,    &selabel_property_init, //最终在该函数中设置selabel_handle结构体内容};struct selabel_handle *selabel_open(unsigned int backend,                    const struct selinux_opt *opts,                    unsigned nopts){    ...    if ((*initfuncs[backend/* 4 selabel_property_init*/])(rec, opts, nopts)) {        free(rec);        rec = NULL;    }    ...}static struct selabel_lookup_rec *selabel_lookup_common(struct selabel_handle *rec,              const char *key, int type){    struct selabel_lookup_rec *lr;    lr = rec->func_lookup(rec, key, type); //libselinux/src/label_android_property.c : lookup函数    if (!lr)        return NULL;    return lr;}int selabel_lookup(struct selabel_handle *rec, char **con,           const char *key, int type){    ...    lr = selabel_lookup_common(rec, key, type);    ...}

libselinux/src/label_android_property.c

static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,                      const char *key,                      int __attribute__((unused)) type){    struct saved_data *data = (struct saved_data *)rec->data;    spec_t *spec_arr = data->spec_arr;    unsigned int i;    struct selabel_lookup_rec *ret = NULL;    if (!data->nspec) {        errno = ENOENT;        goto finish;    }    for (i = 0; i < data->nspec; i++) {        if (strncmp(spec_arr[i].property_key, key,             strlen(spec_arr[i].property_key)) == 0) {   //取service_contexts中的service name,                                                        //并且根据该service name的字符串长度n                                                        //与addService("xxx", this)中的xxxn个字符比较            break;        }        if (strncmp(spec_arr[i].property_key, "*", 1) == 0)            break;    }    if (i >= data->nspec) {        /* No matching specification. */        errno = ENOENT;        goto finish;    }    ret = &spec_arr[i].lr;finish:    return ret;}int selabel_property_init(struct selabel_handle *rec,              const struct selinux_opt *opts,              unsigned nopts){    struct saved_data *data;    data = (struct saved_data *)malloc(sizeof(*data));    if (!data)        return -1;    memset(data, 0, sizeof(*data));    rec->data = data;    rec->func_close = &closef;    rec->func_stats = &stats;    rec->func_lookup = &lookup; //初始化selabel_handle : func_lookup函数指针,service name匹配函数    return init(rec, opts, nopts);}

更多相关文章

  1. Android(安卓)Camera Hal 的初步实现1
  2. Java、Android中Math详解
  3. Android(安卓)ril原生代码(C/C++)和java代码部分分析
  4. 【Android】第5章(4) 单选和复选
  5. Android使用mob快速集成分享功能详解
  6. Android热修复之Tinker接入流程
  7. Android(安卓)Intent机制实例详解(1)
  8. Android属性动画、函数动画
  9. android 为桌面图标添加数字角标

随机推荐

  1. Android学习之路四:ImageView
  2. Android关于java.lang.NoClassDefFoundEr
  3. Android 资源文件中的符号含义与说明: @ ?
  4. 平时积累(四)
  5. Android快速开发框架
  6. android之ListView布局
  7. 安卓手机常见名词解释
  8. MonkeyRunner与模拟器连接
  9. Android应用程序四大组件
  10. Android的布局控件----LinearLayout(线性