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();
}
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;
}
    看到open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC |O_EXCL, 0444); 和 pa = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 我们知道文件property_filename (即 /dev/__properties__)被打开,并以读写可共享的方式 映射到了内存。(其他全局变量,如pa_data_size和__system_property_area__ 暂放置一边, 也不细节的讲述get_fd_from_env() )。

     property_set/property_get位于libcutils.so库,任何进程若要调用这两个函数,需要链接libcutils.so。libcutils.so调用了__system_property_set和__system_Property_get函数,这两个函数位于bionic库中,生成的库文件为libc_common.so。

bionic/libc/bionic/system_properties.c

int __system_property_set(const char *key, const char *value)
{
    int err;
    prop_msg msg;

    if(key == 0) return -1;
    if(value == 0) value = "";
    if(strlen(key) >= PROP_NAME_MAX) return -1;
    if(strlen(value) >= PROP_VALUE_MAX) return -1;

    memset(&msg, 0, sizeof msg);
    msg.cmd = PROP_MSG_SETPROP;
    strlcpy(msg.name, key, sizeof msg.name);
    strlcpy(msg.value, value, sizeof msg.value);

    err = send_prop_msg(&msg);
    if(err < 0) {
        return err;
    }

    return 0;
}
static int send_prop_msg(prop_msg *msg)
{
    struct pollfd pollfds[1];
    struct sockaddr_un addr;
    socklen_t alen;
    size_t namelen;
    int s;
    int r;
    int result = -1;

    s = socket(AF_LOCAL, SOCK_STREAM, 0);
    if(s < 0) {
        return result;
    }

    memset(&addr, 0, sizeof(addr));
    namelen = strlen(property_service_socket);
    strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);
    addr.sun_family = AF_LOCAL;
    alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;

    if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen)) < 0) {
        close(s);
        return result;
    }

    r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));

    if(r == sizeof(prop_msg)) {
        // We successfully wrote to the property server but now we
        // wait for the property server to finish its work.  It
        // acknowledges its completion by closing the socket so we
        // poll here (on nothing), waiting for the socket to close.
        // If you 'adb shell setprop foo bar' you'll see the POLLHUP
        // once the socket closes.  Out of paranoia we cap our poll
        // at 250 ms.
        pollfds[0].fd = s;
        pollfds[0].events = 0;
        r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
        if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) {
            result = 0;
        } else {
            // Ignore the timeout and treat it like a success anyway.
            // The init process is single-threaded and its property
            // service is sometimes slow to respond (perhaps it's off
            // starting a child process or something) and thus this
            // times out and the caller thinks it failed, even though
            // it's still getting around to it.  So we fake it here,
            // mostly for ctl.* properties, but we do try and wait 250
            // ms so callers who do read-after-write can reliably see
            // what they've written.  Most of the time.
            // TODO: fix the system properties design.
            result = 0;
        }
    }

    close(s);
    return result;
}
    property_service.c收到这个msg后,会根据msg.name和msg.value来设置具体的property,在这路需要说明一下,如果根据name能够找到对应的prop_info信息,那么就去update对应的value值,如果找不到对应的prop_info信息,那么就去add一个prop_info。具体flow如下:

system/core/libcutils/properties.c

int property_set(const char *key, const char *value)
{
    char sendBuf[1+PROPERTY_KEY_MAX+PROPERTY_VALUE_MAX];
    char recvBuf[1];
    int result = -1;

    //ALOGV("PROPERTY SET [%s]: [%s]\n", key, value);

    pthread_once(&gInitOnce, init);
    if (gPropFd < 0)
        return -1;

    if (strlen(key) >= PROPERTY_KEY_MAX) return -1;
    if (strlen(value) >= PROPERTY_VALUE_MAX) return -1;

    memset(sendBuf, 0xdd, sizeof(sendBuf));    // placate valgrind

    sendBuf[0] = (char) kSystemPropertySet;
    strcpy(sendBuf+1, key);
    strcpy(sendBuf+1+PROPERTY_KEY_MAX, value);

    pthread_mutex_lock(&gPropertyFdLock);
    if (write(gPropFd, sendBuf, sizeof(sendBuf)) != sizeof(sendBuf)) {
        pthread_mutex_unlock(&gPropertyFdLock);
        return -1;
    }
    if (read(gPropFd, recvBuf, sizeof(recvBuf)) != sizeof(recvBuf)) {
        pthread_mutex_unlock(&gPropertyFdLock);
        return -1;
    }
    pthread_mutex_unlock(&gPropertyFdLock);

    if (recvBuf[0] != 1)
        return -1;
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值