(Android系统)android property浅析

android property,相信各位android平台的开发人员用到的不会少,但是property的具体机制大家可能知道的不多,这里利用空闲时间大致了解了一些,特此分享跟大家,如有谬误,欢迎指正


android 1号进程进程init进程在开机的时候就会调用property_init函数,至于init是怎么起来的,这里不是重点,所以暂时先不介绍,property_init的具体flow如下:
system/core/init/init.c
void property_init(void)
{
    init_property_area();                                                                                                         
}

system/core/init/property_service.c
static int init_property_area(void)                                                                                               
{
    if (property_area_inited)
        return -1;


    if(__system_property_area_init())
        return -1;


    if(init_workspace(&pa_workspace, 0))
        return -1;


    fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);


    property_area_inited = 1;
    return 0;
}

bionic/libc/bionic/system_properties.c
int __system_property_area_init()
{
    return map_prop_area_rw();                                                                                                     
}

把property_filename映射到共享内存,之所以要使用共享内存是因为其他进程也需要使用property,这个是property的最基本功能,注意这里有一个全局变量__system_property_area__很重要,这个是以后所有property的root,也就是说通过这个变量就可以遍历其他property


具体property file的路径如下:

cheny.le@cheny-desktop:~/kitkat2_git/bionic$ grep property_filename * -nr
libc/bionic/system_properties.c:111:static char property_filename[PATH_MAX] = PROP_FILENAME;
cheny.le@cheny-desktop:~/kitkat2_git/bionic$ grep PROP_FILENAME * -nr
libc/include/sys/_system_properties.h:44:#define PROP_FILENAME "/dev/__properties__"

bionic/libc/bionic/system_properties.c
static int map_prop_area_rw()
{
    prop_area *pa;
    int fd;
    int ret;


    /* dev is a tmpfs that we can use to carve a shared workspace
     * out of, so let's do that...
     */
    fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC |
            O_EXCL, 0444);
    if (fd < 0) {
        if (errno == EACCES) {
            /* for consistency with the case where the process has already
             * mapped the page in and segfaults when trying to write to it
             */
            abort();
        }
        return -1;
    }


    ret = fcntl(fd, F_SETFD, FD_CLOEXEC);
    if (ret < 0)
        goto out;


    if (ftruncate(fd, PA_SIZE) < 0)
        goto out;


    pa_size = PA_SIZE;
    pa_data_size = pa_size - sizeof(prop_area);                                                                                    
    compat_mode = false;


    pa = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if(pa == MAP_FAILED)
        goto out;


    memset(pa, 0, pa_size);
    pa->magic = PROP_AREA_MAGIC;
    pa->version = PROP_AREA_VERSION;
    /* reserve root node */
    pa->bytes_used = sizeof(prop_bt);


    /* plug into the lib property services */
    __system_property_area__ = pa;


    close(fd);
    return 0;


out:
    close(fd);
    return -1;
}


property init之后就需要加载boot所需的default property,跟property相关的文件定义如下:
cheny.le@cheny-desktop:~/kitkat2_git/bionic$ grep PROP_PATH_SYSTEM_BUILD * -nr
libc/include/sys/_system_properties.h:82:#define PROP_PATH_SYSTEM_BUILD     "/system/build.prop"
cheny.le@cheny-desktop:~/kitkat2_git/bionic$ grep PROP_PATH_SYSTEM_DEFAULT * -nr
libc/include/sys/_system_properties.h:83:#define PROP_PATH_SYSTEM_DEFAULT   "/system/default.prop"
cheny.le@cheny-desktop:~/kitkat2_git/bionic$ grep PROP_PATH_RAMDISK_DEFAULT * -nr
libc/include/sys/_system_properties.h:81:#define PROP_PATH_RAMDISK_DEFAULT  "/default.prop"


system/core/init/init.c
void property_load_boot_defaults(void)
{
    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT);                                                                         
}

system/core/init/property_service.c
static void load_properties_from_file(const char *fn)                                                                             
{
    char *data;
    unsigned sz; 


    data = read_file(fn, &sz);


    if(data != 0) {
        load_properties(data);
        free(data);
    }   
}


read file的作用就是把file的内容读到buffer里面,然后确保以'/0'结尾
system/core/init/util.c
void *read_file(const char *fn, unsigned *_sz)
{
    char *data;
    int sz;
    int fd;
    struct stat sb;


    data = 0;
    fd = open(fn, O_RDONLY);
    if(fd < 0) return 0;


    // for security reasons, disallow world-writable
    // or group-writable files
    if (fstat(fd, &sb) < 0) {
        ERROR("fstat failed for '%s'\n", fn);
        goto oops;
    }
    if ((sb.st_mode & (S_IWGRP | S_IWOTH)) != 0) {
        ERROR("skipping insecure file '%s'\n", fn);
        goto oops;
    }


    sz = lseek(fd, 0, SEEK_END);
    if(sz < 0) goto oops;


    if(lseek(fd, 0, SEEK_SET) != 0) goto oops;


    data = (char*) malloc(sz + 2);
    if(data == 0) goto oops;


    if(read(fd, data, sz) != sz) goto oops;
    close(fd);
    data[sz] = '\n';
    data[sz+1] = 0;
    if(_sz) *_sz = sz;
    return data;


oops:
    close(fd);
    if(data != 0) free(data);
    return 0;
}

把buffer的内容按指定格式解析出来,然后用property_set设置到系统中,具体property_set的流程后续给出具体解释
system/core/init/property_service.c
static void load_properties(char *data)                                                                                           
{
    char *key, *value, *eol, *sol, *tmp;


    sol = data;
    while((eol = strchr(sol, '\n'))) {
        key = sol;
        *eol++ = 0;
        sol = eol;


        value = strchr(key, '=');
        if(value == 0) continue;
        *value++ = 0;


        while(isspace(*key)) key++;
        if(*key == '#') continue;
        tmp = value - 2;
        while((tmp > key) && isspace(*tmp)) *tmp-- = 0;


        while(isspace(*value)) value++;
        tmp = eol - 2;
        while((tmp > value) && isspace(*tmp)) *tmp-- = 0;


        property_set(key, value);
    }
}


init的main里面接下来会跑property的service,这个service会首先加载system build和system defaule两个property文件,然后创建socket用来监听bionic 里面system_properties.c发送过来的事件,关于事件的解析后续会进行分析
cheny.le@cheny-desktop:~/kitkat2_git/bionic$ grep  PROP_SERVICE_NAME * -nr
libc/include/sys/_system_properties.h:43:#define PROP_SERVICE_NAME "property_service"

void start_property_service(void)
{
    int fd;


    load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
    load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);                                                                          
    load_override_properties();
    /* Read persistent properties after all default values have been loaded. */
    load_persistent_properties();


    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0);
    if(fd < 0) return;
    fcntl(fd, F_SETFD, FD_CLOEXEC);
    fcntl(fd, F_SETFL, O_NONBLOCK);


    listen(fd, 8);
    property_set_fd = fd;
}


cheny.le@cheny-desktop:~/kitkat2_git/system/core$ grep ANDROID_SOCKET_DIR * -nr
include/cutils/sockets.h:33:#define ANDROID_SOCKET_DIR		"/dev/socket"
这也就是说会建立一个/dev/socket/property_service的socket,然后listen这个socket


int create_socket(const char *name, int type, mode_t perm, uid_t uid, gid_t gid)
{
    struct sockaddr_un addr;
    int fd, ret;
    char *secon;


    fd = socket(PF_UNIX, type, 0);
    if (fd < 0) {
        ERROR("Failed to open socket '%s': %s\n", name, strerror(errno));
        return -1;
    }


    memset(&addr, 0 , sizeof(addr));
    addr.sun_family = AF_UNIX;
    snprintf(addr.sun_path, sizeof(addr.sun_path), ANDROID_SOCKET_DIR"/%s",
             name);


    ret = unlink(addr.sun_path);
    if (ret != 0 && errno != ENOENT) {
        ERROR("Failed to unlink old socket '%s': %s\n", name, strerror(errno));
        goto out_close;
    }


    secon = NULL;
    if (sehandle) {
        ret = selabel_lookup(sehandle, &secon
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值