Android System Properties

来源:互联网 发布:网络信息安全保护小组 编辑:程序博客网 时间:2024/05/02 05:07

学习System Properties

根据5.1的系统源码细节稍有不同。

转自:http://stevevallay.github.io/blog/2013/12/23/android-system-properties2/

system/core/init/init.c

property_init();

system/core/init/property_service.c

void property_init(void){    init_property_area();}

static int init_property_area(void){    if (property_area_inited)        return -1;    if(__system_property_area_init())//关键        return -1;//初始化workspace,得到shared memory的fd,size,data    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.cpp

int __system_property_area_init(){    return map_prop_area_rw();}

static int map_prop_area_rw(){    /* dev is a tmpfs that we can use to carve a shared workspace     * out of, so let's do that...     */    const int fd = open(property_filename,   //static char property_filename[PATH_MAX] = PROP_FILENAME;    //在头文件中#define PROP_FILENAME "/dev/__properties__"                        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;    }    // TODO: Is this really required ? Does android run on any kernels that    // don't support O_CLOEXEC ?    const int ret = fcntl(fd, F_SETFD, FD_CLOEXEC);//linux里面的函数    if (ret < 0) {        close(fd);        return -1;    }    if (ftruncate(fd, PA_SIZE) < 0) {        close(fd);        return -1;    }    pa_size = PA_SIZE;    pa_data_size = pa_size - sizeof(prop_area);    compat_mode = false;    void *const memory_area = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);//用mmap映射到内存    if (memory_area == MAP_FAILED) {        close(fd);        return -1;    }    prop_area *pa = new(memory_area) prop_area(PROP_AREA_MAGIC, PROP_AREA_VERSION);    /* plug into the lib property services */    __system_property_area__ = pa;//通过该变量共享,完成property_service和libc中properties相关的交互    close(fd);    return 0;}


继续到init.c

init.c

INFO("property init\n");    property_load_boot_defaults();

property_service.c:

void property_load_boot_defaults(void){    load_properties_from_file(PROP_PATH_RAMDISK_DEFAULT, NULL);}
/* * Filter is used to decide which properties to load: NULL loads all keys, * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match. */static void load_properties_from_file(const char *fn, const char *filter){    char *data;    unsigned sz;    data = read_file(fn, &sz);    if(data != 0) {        load_properties(data, filter);        free(data);    }}
/* * Filter is used to decide which properties to load: NULL loads all keys, * "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match. */static void load_properties(char *data, const char *filter){    char *key, *value, *eol, *sol, *tmp, *fn;    size_t flen = 0;    if (filter) {        flen = strlen(filter);    }    sol = data;    while ((eol = strchr(sol, '\n'))) {        key = sol;        *eol++ = 0;        sol = eol;        while (isspace(*key)) key++;        if (*key == '#') continue;        tmp = eol - 2;        while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;        if (!strncmp(key, "import ", 7) && flen == 0) {            fn = key + 7;            while (isspace(*fn)) fn++;            key = strchr(fn, ' ');            if (key) {                *key++ = 0;                while (isspace(*key)) key++;            }            load_properties_from_file(fn, key);        } else {            value = strchr(key, '=');            if (!value) continue;            *value++ = 0;            tmp = value - 2;            while ((tmp > key) && isspace(*tmp)) *tmp-- = 0;            while (isspace(*value)) value++;            if (flen > 0) {                if (filter[flen - 1] == '*') {                    if (strncmp(key, filter, flen - 1)) continue;                } else {                    if (strcmp(key, filter)) continue;                }            }            property_set(key, value);//初始化property        }    }}

init.c 启动property service

queue_builtin_action(property_service_init_action, "property_service_init");
static int property_service_init_action(int nargs, char **args){    /* read any property files on system or data and     * fire up the property service.  This must happen     * after the ro.foo properties are set above so     * that /data/local.prop cannot interfere with them.     */    start_property_service();    if (get_property_set_fd() < 0) {        ERROR("start_property_service() failed\n");        exit(1);    }    return 0;}

property_service.c:

void start_property_service(void){    int fd;    fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 0666, 0, 0, NULL);//创建socket来接受set property的消息    if(fd < 0) return;    fcntl(fd, F_SETFD, FD_CLOEXEC);    fcntl(fd, F_SETFL, O_NONBLOCK);    listen(fd, 8);    property_set_fd = fd;}

init.c

init进程最后,进入一个无限循环,等待/dev/socket/property_service和其他fd事件,并处理

   for(;;) {        int nr, i, timeout = -1;        execute_one_command();        restart_processes();        if (!property_set_fd_init && get_property_set_fd() > 0) {            ufds[fd_count].fd = get_property_set_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            property_set_fd_init = 1;        }        if (!signal_fd_init && get_signal_fd() > 0) {            ufds[fd_count].fd = get_signal_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            signal_fd_init = 1;        }        if (!keychord_fd_init && get_keychord_fd() > 0) {            ufds[fd_count].fd = get_keychord_fd();            ufds[fd_count].events = POLLIN;            ufds[fd_count].revents = 0;            fd_count++;            keychord_fd_init = 1;        }        if (process_needs_restart) {            timeout = (process_needs_restart - gettime()) * 1000;            if (timeout < 0)                timeout = 0;        }        if (!action_queue_empty() || cur_action)            timeout = 0;#if BOOTCHART        if (bootchart_count > 0) {            if (timeout < 0 || timeout > BOOTCHART_POLLING_MS)                timeout = BOOTCHART_POLLING_MS;            if (bootchart_step() < 0 || --bootchart_count == 0) {                bootchart_finish();                bootchart_count = 0;            }        }#endif        nr = poll(ufds, fd_count, timeout);        if (nr <= 0)            continue;        for (i = 0; i < fd_count; i++) {            if (ufds[i].revents & POLLIN) {                if (ufds[i].fd == get_property_set_fd())                    handle_property_set_fd();    //接受/dev/socket/property_service的消息并处理                else if (ufds[i].fd == get_keychord_fd())                    handle_keychord();                else if (ufds[i].fd == get_signal_fd())                    handle_signal();            }        }    }    return 0;}

property_service.c

void handle_property_set_fd(){    prop_msg msg;    int s;    int r;    int res;    struct ucred cr;    struct sockaddr_un addr;    socklen_t addr_size = sizeof(addr);    socklen_t cr_size = sizeof(cr);    char * source_ctx = NULL;    struct pollfd ufds[1];    const int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */    int nr;    if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {        return;    }    /* Check socket options here */    if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {        close(s);        ERROR("Unable to receive socket options\n");        return;    }    ufds[0].fd = s;    ufds[0].events = POLLIN;    ufds[0].revents = 0;    nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));    if (nr == 0) {        ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);        close(s);        return;    } else if (nr < 0) {        ERROR("sys_prop: error waiting for uid=%d to send property message. err=%d %s\n", cr.uid, errno, strerror(errno));        close(s);        return;    }    r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));    if(r != sizeof(prop_msg)) {        ERROR("sys_prop: mis-match msg size received: %d expected: %zu errno: %d\n",              r, sizeof(prop_msg), errno);        close(s);        return;    }    switch(msg.cmd) {    case PROP_MSG_SETPROP:     //处理set proper请求        msg.name[PROP_NAME_MAX-1] = 0;        msg.value[PROP_VALUE_MAX-1] = 0;        if (!is_legal_property_name(msg.name, strlen(msg.name))) {            ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);            close(s);            return;        }        getpeercon(s, &source_ctx);        if(memcmp(msg.name,"ctl.",4) == 0) {            // Keep the old close-socket-early behavior when handling            // ctl.* properties.            close(s);            if (check_control_mac_perms(msg.value, source_ctx)) {                handle_control_message((char*) msg.name + 4, (char*) msg.value);            } else {                ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",                        msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);            }        } else {            if (check_perms(msg.name, source_ctx)) {                property_set((char*) msg.name, (char*) msg.value);  //如果有permission,则设置property            } else {                ERROR("sys_prop: permission denied uid:%d  name:%s\n",                      cr.uid, msg.name);            }            // Note: bionic's property client code assumes that the            // property server will not close the socket until *AFTER*            // the property is written to memory.            close(s);        }        freecon(source_ctx);        break;    default:        close(s);        break;    }}

check_perms不同的property_set需要不同的权限


/* White list of permissions for setting property services. */struct {    const char *prefix;    unsigned int uid;    unsigned int gid;} property_perms[] = {    { "net.rmnet0.",      AID_RADIO,    0 },    { "net.gprs.",        AID_RADIO,    0 },    { "net.ppp",          AID_RADIO,    0 },    { "net.qmi",          AID_RADIO,    0 },    { "net.lte",          AID_RADIO,    0 },    { "net.cdma",         AID_RADIO,    0 },    { "ril.",             AID_RADIO,    0 },    { "gsm.",             AID_RADIO,    0 },    { "persist.radio",    AID_RADIO,    0 },    { "net.dns",          AID_RADIO,    0 },    { "sys.usb.config",   AID_RADIO,    0 },    { "net.",             AID_SYSTEM,   0 },    { "dev.",             AID_SYSTEM,   0 },    { "runtime.",         AID_SYSTEM,   0 },    { "hw.",              AID_SYSTEM,   0 },    { "sys.",             AID_SYSTEM,   0 },    { "sys.powerctl",     AID_SHELL,    0 },    { "service.",         AID_SYSTEM,   0 },    { "wlan.",            AID_SYSTEM,   0 },    { "gps.",             AID_GPS,      0 },    { "bluetooth.",       AID_BLUETOOTH,   0 },    { "dhcp.",            AID_SYSTEM,   0 },    { "dhcp.",            AID_DHCP,     0 },    { "debug.",           AID_SYSTEM,   0 },    { "debug.",           AID_SHELL,    0 },    { "log.",             AID_SHELL,    0 },    { "service.adb.root", AID_SHELL,    0 },    { "service.adb.tcp.port", AID_SHELL,    0 },    { "persist.logd.size",AID_SYSTEM,   0 },    { "persist.sys.",     AID_SYSTEM,   0 },    { "persist.service.", AID_SYSTEM,   0 },    { "persist.security.", AID_SYSTEM,   0 },    { "persist.gps.",      AID_GPS,      0 },    { "persist.service.bdroid.", AID_BLUETOOTH,   0 },    { "selinux."         , AID_SYSTEM,   0 },    { "wc_transport.",     AID_BLUETOOTH,   AID_SYSTEM },    { "build.fingerprint", AID_SYSTEM,   0 },    { "partition."        , AID_SYSTEM,   0},    { NULL, 0, 0 }};

property_set:

int property_set(const char *name, const char *value){    prop_info *pi;    int ret;    size_t namelen = strlen(name);    size_t valuelen = strlen(value);    if (!is_legal_property_name(name, namelen)) return -1;    if (valuelen >= PROP_VALUE_MAX) return -1;    pi = (prop_info*) __system_property_find(name);    if(pi != 0) {//如果有个这个property        /* ro.* properties may NEVER be modified once set */        if(!strncmp(name, "ro.", 3)) return -1;        __system_property_update(pi, value, valuelen);    } else {        ret = __system_property_add(name, namelen, value, valuelen);        if (ret < 0) {            ERROR("Failed to set '%s'='%s'\n", name, value);            return ret;        }    }    /* If name starts with "net." treat as a DNS property. */    if (strncmp("net.", name, strlen("net.")) == 0)  {        if (strcmp("net.change", name) == 0) {            return 0;        }       /*        * The 'net.change' property is a special property used track when any        * 'net.*' property name is updated. It is _ONLY_ updated here. Its value        * contains the last updated 'net.*' property.        */        property_set("net.change", name);    } else if (persistent_properties_loaded &&            strncmp("persist.", name, strlen("persist.")) == 0) {//如果是persist.开头的文件,写入到/data/property/***        /*         * Don't write properties to disk until after we have read all default properties         * to prevent them from being overwritten by default values.         */        write_persistent_property(name, value);    } else if (strcmp("selinux.reload_policy", name) == 0 &&               strcmp("1", value) == 0) {        selinux_reload_policy();    }    property_changed(name, value);    return 0;}

static void write_persistent_property(const char *name, const char *value){    char tempPath[PATH_MAX];    char path[PATH_MAX];    int fd;    snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);    fd = mkstemp(tempPath);    if (fd < 0) {        ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno);        return;    }    write(fd, value, strlen(value));    fsync(fd);    close(fd);    snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);    if (rename(tempPath, path)) {        unlink(tempPath);        ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path);    }}



下面看看proper_get 直接向下到libc的__system_property_get的api

property_service.c

int __property_get(const char *name, char *value){    return __system_property_get(name, value);}


bionic/libc/bionic/system_properties.cpp

int __system_property_get(const char *name, char *value){    const prop_info *pi = __system_property_find(name);    if (pi != 0) {        return __system_property_read(pi, 0, value);    } else {        value[0] = 0;        return 0;    }}


调用__system_property_find

const prop_info *__system_property_find(const char *name){    if (__predict_false(compat_mode)) {        return __system_property_find_compat(name);    }    return find_property(root_node(), name, strlen(name), NULL, 0, false);}


其中root_node()

static prop_bt *root_node(){    return reinterpret_cast<prop_bt*>(to_prop_obj(0));}

static void *to_prop_obj(const uint32_t off){    if (off > pa_data_size)        return NULL;    if (!__system_property_area__)        return NULL;    return (__system_property_area__->data + off);}

实际上获取__system_property_area__->data 的地址开始访问。__system_property_area__是/dev/properties map到内存的地址


在开始时就分析了,init.c进程初始化时,调用proper_service.c的proper_init(),接着进入system_properties.cpp的__system_property_area_(),再进入map_prop_area_rw(),创建property_filename(/dev/_properties_),mmap到内存,将地址赋值给__system_property_area__

static int map_prop_area_rw(){    /* dev is a tmpfs that we can use to carve a shared workspace     * out of, so let's do that...     */    const int fd = open(property_filename,                        O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);  //......    void *const memory_area = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);   //......    prop_area *pa = new(memory_area) prop_area(PROP_AREA_MAGIC, PROP_AREA_VERSION);    /* plug into the lib property services */    __system_property_area__ = pa;    close(fd);    return 0;}

其他进程调用__system_property_find时不可以直接访问init进程里面的__system_property_area__,他们不能共享这个地址,不同进程之间各自使用自己独享的内存空间。

其他进程也对__system_property_area__初始化了一下。




0 0
原创粉丝点击