linux源码版本-->3.4
一. 总体分析
二.property的初始化
system/core/init.c中会调用property_init,
-
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;
-
-
if(init_workspace(&pa_workspace, 0))
-
return -1;
-
-
fcntl(pa_workspace.fd, F_SETFD, FD_CLOEXEC);
-
-
property_area_inited = 1;
-
return 0;
- }
-
int __system_property_area_init()
-
{
-
return map_prop_area_rw();
- }
-
static int map_prop_area_rw()
-
{
-
prop_area *pa;
-
int fd;
-
int ret;
-
- //打开/dev/__properties__文件
-
//static char property_filename[PATH_MAX] = PROP_FILENAME;
//#define PROP_FILENAME "/dev/__properties__" - fd = open(property_filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
-
if (fd < 0) {
-
if (errno == EACCES) {
- abort();
-
}
-
return -1;
-
}
-
-
ret = fcntl(fd, F_SETFD, FD_CLOEXEC); //FD_CLOEXEC表示执行exec函数时fd会关闭
-
if (ret < 0)
-
goto out;
-
//把文件设为128K大小
-
if (ftruncate(fd, PA_SIZE) < 0) //include/sys/_system_properties.h中定义了#define PA_SIZE (128 * 1024)
-
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;
-
//把映射的128K字段清0,同时共享内存的开始是结构体pa,设置一下pa
-
memset(pa, 0, pa_size);
-
pa->magic = PROP_AREA_MAGIC;
-
pa->version = PROP_AREA_VERSION;
- pa->bytes_used = sizeof(prop_bt);
-
-
/* plug into the lib property services */
-
__system_property_area__ = pa; //将全局变量__system_property_area__作为管理结构体
-
-
close(fd);
-
return 0;
-
-
out:
-
close(fd);
-
return -1;
- }
三.property的读取与设置
以init/init.c中的export_kernel_boot_props为例说明
-
static void export_kernel_boot_props(void)
-
{
- struct {
-
const char *src_prop;
-
const char *dest_prop;
-
const char *def_val;
-
} prop_map[] = {
-
{ "ro.boot.serialno", "ro.serialno", "", },
-
{ "ro.boot.mode", "ro.bootmode", "unknown", },
-
{ "ro.boot.baseband", "ro.baseband", "unknown", },
-
{ "ro.boot.bootloader", "ro.bootloader", "unknown", },
-
};
-
for (i = 1; i < ARRAY_SIZE(prop_map); i++) {
-
ret = property_get(prop_map[i].src_prop, tmp); //先获取perperty中的字段,如果ret>0,说明找到了
-
if (ret > 0)
-
property_set(prop_map[i].dest_prop, tmp);
-
else
-
property_set(prop_map[i].dest_prop, prop_map[i].def_val);
-
}
-
......
- }
3.1 读取的过程:在system/core/libcutils/properties.c中
因为在build/core/combo/include/arch/linux-arm/AndroidConfig.h中定义了HAVE_LIBC_SYSTEM_PROPERTIES,
所以poperty_get的实现如下所示:
-
int property_get(const char *key, char *value, const char *default_value)
-
{
-
int len;
-
-
len = __system_property_get(key, value); //先去查找
-
if(len > 0) {
-
return len;
-
}
-
//如果没有找到,并且default_value不为空,就将value设为default_value
-
if(default_value) {
-
len = strlen(default_value);
-
memcpy(value, default_value, len + 1);
-
}
-
return len;
- }
-
int __system_property_get(const char *name, char *value)
-
{
-
const prop_info *pi = __system_property_find(name); //先在mmap的共享内存中查找结点是否存在
-
-
if(pi != 0) { //如果存在就去读取其value
-
return __system_property_read(pi, 0, value);
-
} else { //如果不存在就把value设为0,注意value是个字符串
-
value[0] = 0;
-
return 0;
-
}
- }
3.2 写入的过程:在system/core/libcutils/properties.c中
-
int property_set(const char *key, const char *value)
-
{
-
return __system_property_set(key, value);
- }
-
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;
-
//构造msg
-
memset(&msg, 0, sizeof msg);
-
msg.cmd = PROP_MSG_SETPROP;
-
strlcpy(msg.name, key, sizeof msg.name);
-
strlcpy(msg.value, value, sizeof msg.value);
-
//发送msg
-
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); //创建一个本地socket
-
if(s < 0) {
-
return result;
-
}
-
-
memset(&addr, 0, sizeof(addr));
-
namelen = strlen(property_service_socket); //这个路径是/dev/socket/property_service
-
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) { //连接到server
-
close(s);
-
return result;
-
}
-
-
r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0)); //发送数据到server
-
-
if(r == sizeof(prop_msg)) { //如果发送成功
- pollfds[0].fd = s;
-
pollfds[0].events = 0;
-
r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */)); //则创建poll来监听server的回应
-
if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) {
-
result = 0;
-
} else {
- result = 0;
-
}
-
}
-
-
close(s);
-
return result;
- }
3.2.2 server是在哪开启的呢
init/init.c中--> 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();
-
return 0;
- }
-
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; //把这个server的socket fd设为全局变量
-
#ifdef AW_BOOSTUP_ENABLE
-
aw_init_boostup();
-
#endif
- }
3.2.3 在init的最后
-
int main(int argc, char **argv)
-
{
- .......
-
for(;;) {
-
int nr, i, timeout = -1;
-
-
execute_one_command();
-
restart_processes();
-
-
if (!property_set_fd_init && get_property_set_fd() > 0) { //这个get_property_set_fd就是获取全局变量propety_set_fd
-
ufds[fd_count].fd = get_property_set_fd(); //把server端的socket fd 放到poll中监听
-
ufds[fd_count].events = POLLIN;
-
ufds[fd_count].revents = 0;
-
fd_count++;
-
property_set_fd_init = 1;
-
}
- ....
-
nr = poll(ufds, fd_count, timeout); //在poll中监听socket fd
-
if (nr <= 0)
-
continue;
-
-
for (i = 0; i < fd_count; i++) {
-
if (ufds[i].revents == POLLIN) {
-
if (ufds[i].fd == get_property_set_fd()) //如果是property的fd有变化则调用property的函数去处理
-
handle_property_set_fd();
-
else if (ufds[i].fd == get_keychord_fd())
-
handle_keychord();
-
else if (ufds[i].fd == get_signal_fd())
-
handle_signal();
-
}
-
}
-
}
-
-
return 0;
- }
-
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;
-
-
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;
-
}
-
-
r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
-
if(r != sizeof(prop_msg)) {
-
ERROR("sys_prop: mis-match msg size received: %d expected: %d errno: %d\n",
-
r, sizeof(prop_msg), errno);
-
close(s);
-
return;
-
}
-
-
switch(msg.cmd) {
-
case PROP_MSG_SETPROP:
-
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) { //处理ctl.开头消息
- close(s);
-
if (check_control_perms(msg.value, cr.uid, cr.gid, 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, cr.uid, cr.gid, source_ctx)) {
-
property_set((char*) msg.name, (char*) msg.value); //真正的property_set
-
} 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;
-
}
- }