android6.0 属性

http://blog.csdn.net/kc58236582/article/details/51939322


属性在Android中非常重要,我们基本的不多介绍了,主要说下其用法,原理等。


一、java层获取属性

Java层主要通过SystemProperties这个类来访问android的系统属性,通过一系列的native函数。

[cpp]  view plain  copy
  1. public class SystemProperties  
  2. {  
  3.     ......  
  4.   
  5.     public static String get(String key) {  
  6.         if (key.length() > PROP_NAME_MAX) {  
  7.             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);  
  8.         }  
  9.         return native_get(key);  
  10.     }  
  11.   
  12.     public static String get(String key, String def) {  
  13.         if (key.length() > PROP_NAME_MAX) {  
  14.             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);  
  15.         }  
  16.         return native_get(key, def);  
  17.     }  
  18.   
  19.     public static int getInt(String key, int def) {  
  20.         if (key.length() > PROP_NAME_MAX) {  
  21.             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);  
  22.         }  
  23.         return native_get_int(key, def);  
  24.     }  
  25.   
  26.     public static long getLong(String key, long def) {  
  27.         if (key.length() > PROP_NAME_MAX) {  
  28.             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);  
  29.         }  
  30.         return native_get_long(key, def);  
  31.     }  
  32.   
  33.     public static boolean getBoolean(String key, boolean def) {  
  34.         if (key.length() > PROP_NAME_MAX) {  
  35.             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);  
  36.         }  
  37.         return native_get_boolean(key, def);  
  38.     }  
  39.   
  40.     public static void set(String key, String val) {  
  41.         if (key.length() > PROP_NAME_MAX) {  
  42.             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);  
  43.         }  
  44.         if (val != null && val.length() > PROP_VALUE_MAX) {  
  45.             throw new IllegalArgumentException("val.length > " +  
  46.                 PROP_VALUE_MAX);  
  47.         }  
  48.         native_set(key, val);  
  49.     }  

我们再来看下android_os_SystemProperties.cpp中的这些native函数,注意都是静态的,因为在java层也是静态调用。

[cpp]  view plain  copy
  1. static jboolean SystemProperties_get_boolean(JNIEnv *env, jobject clazz,  
  2.                                       jstring keyJ, jboolean defJ)  
  3. {  
  4.     int len;  
  5.     const char* key;  
  6.     char buf[PROPERTY_VALUE_MAX];  
  7.     jboolean result = defJ;  
  8.   
  9.     if (keyJ == NULL) {  
  10.         jniThrowNullPointerException(env, "key must not be null.");  
  11.         goto error;  
  12.     }  
  13.   
  14.     key = env->GetStringUTFChars(keyJ, NULL);  
  15.   
  16.     len = property_get(key, buf, "");  
  17.     if (len == 1) {  
  18.         char ch = buf[0];  
  19.         if (ch == '0' || ch == 'n')  
  20.             result = false;  
  21.         else if (ch == '1' || ch == 'y')  
  22.             result = true;  
  23.     } else if (len > 1) {  
  24.          if (!strcmp(buf, "no") || !strcmp(buf, "false") || !strcmp(buf, "off")) {  
  25.             result = false;  
  26.         } else if (!strcmp(buf, "yes") || !strcmp(buf, "true") || !strcmp(buf, "on")) {  
  27.             result = true;  
  28.         }  
  29.     }  
  30.   
  31.     env->ReleaseStringUTFChars(keyJ, key);  
  32.   
  33. error:  
  34.     return result;  
  35. }  
  36.   
  37. static void SystemProperties_set(JNIEnv *env, jobject clazz,  
  38.                                       jstring keyJ, jstring valJ)  
  39. {  
  40.     int err;  
  41.     const char* key;  
  42.     const char* val;  
  43.   
  44.     if (keyJ == NULL) {  
  45.         jniThrowNullPointerException(env, "key must not be null.");  
  46.         return ;  
  47.     }  
  48.     key = env->GetStringUTFChars(keyJ, NULL);  
  49.   
  50.     if (valJ == NULL) {  
  51.         val = "";       /* NULL pointer not allowed here */  
  52.     } else {  
  53.         val = env->GetStringUTFChars(valJ, NULL);  
  54.     }  
  55.   
  56.     err = property_set(key, val);  
  57.   
  58.     env->ReleaseStringUTFChars(keyJ, key);  
  59.   
  60.     if (valJ != NULL) {  
  61.         env->ReleaseStringUTFChars(valJ, val);  
  62.     }  
  63.   
  64.     if (err < 0) {  
  65.         jniThrowException(env, "java/lang/RuntimeException",  
  66.                           "failed to set system property");  
  67.     }  
  68. }  

最后是调用了system/core/libcutils/properties.c文件中的下面函数

[cpp]  view plain  copy
  1. int property_set(const char *key, const char *value)  
  2. {  
  3.     return __system_property_set(key, value);  
  4. }  
  5.   
  6. int property_get(const char *key, char *value, const char *default_value)  
  7. {  
  8.     int len;  
  9.   
  10.     len = __system_property_get(key, value);  
  11.     if(len > 0) {  
  12.         return len;  
  13.     }  
  14.     if(default_value) {  
  15.         len = strlen(default_value);  
  16.         if (len >= PROPERTY_VALUE_MAX) {  
  17.             len = PROPERTY_VALUE_MAX - 1;  
  18.         }  
  19.         memcpy(value, default_value, len);  
  20.         value[len] = '\0';  
  21.     }  
  22.     return len;  
  23. }  
最后在bionic/libc/bionic/system_properties.cpp中调用如下函数write都是通过socket来往init写属性的,然后在init中调用__system_property_update和__system_property_add来往共享内存中写属性,但是获取属性应该是通过共享内存读取的。
[cpp]  view plain  copy
  1. int __system_property_get(const char *name, char *value)  
  2. {  
  3.     const prop_info *pi = __system_property_find(name);//从共享内存上获取相应的属性内存  
  4.   
  5.     if (pi != 0) {  
  6.         return __system_property_read(pi, 0, value);//从属性内存中读取属性内容  
  7.     } else {  
  8.         value[0] = 0;  
  9.         return 0;  
  10.     }  
  11. }  
  12.   
  13. int __system_property_set(const char *key, const char *value)  
  14. {  
  15.     if (key == 0) return -1;  
  16.     if (value == 0) value = "";  
  17.     if (strlen(key) >= PROP_NAME_MAX) return -1;  
  18.     if (strlen(value) >= PROP_VALUE_MAX) return -1;  
  19.   
  20.     prop_msg msg;  
  21.     memset(&msg, 0, sizeof msg);  
  22.     msg.cmd = PROP_MSG_SETPROP;  
  23.     strlcpy(msg.name, key, sizeof msg.name);  
  24.     strlcpy(msg.value, value, sizeof msg.value);  
  25.   
  26.     const int err = send_prop_msg(&msg);  
  27.     if (err < 0) {  
  28.         return err;  
  29.     }  
  30.   
  31.     return 0;  
  32. }  

有一点需要注意java中还有一个函数System.getProperty获取的不是系统属性,不要混淆了。


二、c层获取属性

c层获取属性我们就是通过上面的property_set和property_get方法

[cpp]  view plain  copy
  1. int property_set(const char *key, const char *value)  
  2. {  
  3.     return __system_property_set(key, value);  
  4. }  
  5.   
  6. int property_get(const char *key, char *value, const char *default_value)  
  7. {  
  8.     int len;  
  9.   
  10.     len = __system_property_get(key, value);  
  11.     if(len > 0) {  
  12.         return len;  
  13.     }  
  14.     if(default_value) {  
  15.         len = strlen(default_value);  
  16.         if (len >= PROPERTY_VALUE_MAX) {  
  17.             len = PROPERTY_VALUE_MAX - 1;  
  18.         }  
  19.         memcpy(value, default_value, len);  
  20.         value[len] = '\0';  
  21.     }  
  22.     return len;  
  23. }  


三、init进程处理属性

系统中的每个进程都可以调用这些函数来读取和修改属性。读取属性值对任何进程都是没有限制的,直接由本进程从共享区中读取;但是修改属性值则必须通过init进程完成,同时进程还需要检查请求的进程是否有权限修改该属性值。

属性值成功修改后,init进程会检查init.rc中是否定义了该属性值的触发器。如果有定义,就执行该触发器下的命令。看下面:

[cpp]  view plain  copy
  1. on property:sys.lc.amtmode=0  
  2.     class_start core  
  3.     class_start main  
  4.     class_start late_start  
  5.     start lc-oms-sa  


3.1 属性分类

我们看下属性的一些分类:

1.ro前缀的,"ro."这样的属性是只读属性,一旦设置,属性值不能再改变了。

2.persist前缀的,"persist."这样的属性改变会写入目录data/property下与属性名相同的文件中。再次开机时这些值会被init进程读取出来,因此关机再启动也是生效的。

3.NET前缀的,"net."这样的属性当它改变时,属性"net.change"将会被自动设置为最后修改的属性名

4.属性"ctl.start" "ctl.stop"和 "ctl.restart"属性控制类属性,用于启动和停止服务的。使用ctl.start启动服务时,系统将会启动结果放在名为"init.svc.服务名”属性中。


3.2 创建属性系统共享空间

property_init 主要是在__system_property_area_init函数中创建了共享内存

[cpp]  view plain  copy
  1. void property_init() {  
  2.     if (property_area_initialized) {  
  3.         return;  
  4.     }  
  5.   
  6.     property_area_initialized = true;  
  7.   
  8.     if (__system_property_area_init()) {  
  9.         return;  
  10.     }  
  11.   
  12.     pa_workspace.size = 0;  
  13.     pa_workspace.fd = open(PROP_FILENAME, O_RDONLY | O_NOFOLLOW | O_CLOEXEC);  
  14.     if (pa_workspace.fd == -1) {  
  15.         ERROR("Failed to open %s: %s\n", PROP_FILENAME, strerror(errno));  
  16.         return;  
  17.     }  
  18. }  

我们来看__system_property_area_init函数,最后是在map_prop_area_rw函数中调用了mmap创建了共享内存

[cpp]  view plain  copy
  1. int __system_property_area_init()  
  2. {  
  3.     return map_prop_area_rw();  
  4. }  
[cpp]  view plain  copy
  1. static int map_prop_area_rw()  
  2. {  
  3.     /* dev is a tmpfs that we can use to carve a shared workspace 
  4.      * out of, so let's do that... 
  5.      */  
  6.     const int fd = open(property_filename,//文件/dev/__properties__,应该是匿名映射,没有实际文件  
  7.                         O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);  
  8.   
  9.     if (fd < 0) {  
  10.         if (errno == EACCES) {  
  11.             /* for consistency with the case where the process has already 
  12.              * mapped the page in and segfaults when trying to write to it 
  13.              */  
  14.             abort();  
  15.         }  
  16.         return -1;  
  17.     }  
  18.   
  19.     if (ftruncate(fd, PA_SIZE) < 0) {  
  20.         close(fd);  
  21.         return -1;  
  22.     }  
  23.   
  24.     pa_size = PA_SIZE;  
  25.     pa_data_size = pa_size - sizeof(prop_area);  
  26.     compat_mode = false;  
  27.   
  28.     void *const memory_area = mmap(NULL, pa_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);//内存映射  
  29.     if (memory_area == MAP_FAILED) {  
  30.         close(fd);  
  31.         return -1;  
  32.     }  
  33.   
  34.     prop_area *pa = new(memory_area) prop_area(PROP_AREA_MAGIC, PROP_AREA_VERSION);  
  35.   
  36.     /* plug into the lib property services */  
  37.     __system_property_area__ = pa;  
  38.   
  39.     close(fd);  
  40.     return 0;  
  41. }  

共享内存使用名称为如下的设备文件创建。

[cpp]  view plain  copy
  1. #define PROP_FILENAME "/dev/__properties__"  


3.3 init进程处理属性


在init进程中的主函数中:在解析init.rc之前,先调用了start_property_service函数

[cpp]  view plain  copy
  1. property_load_amt_defaults(amt_mode);  
  2.   
  3. property_load_boot_defaults();  
  4. start_property_service();  
  5.   
  6. init_parse_config_file("/init.rc");  

start_property_service函数创建了socket,然后监听,并且调用register_epoll_handler函数把socket的fd放入了epoll中

[cpp]  view plain  copy
  1. void start_property_service() {  
  2.     property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,  
  3.                                     0666, 0, 0, NULL);  
  4.     if (property_set_fd == -1) {  
  5.         ERROR("start_property_service socket creation failed: %s\n", strerror(errno));  
  6.         exit(1);  
  7.     }  
  8.   
  9.     listen(property_set_fd, 8);  
  10.   
  11.     register_epoll_handler(property_set_fd, handle_property_set_fd);  
  12. }  

register_epoll_handler函数就是把fd放入epoll中

[cpp]  view plain  copy
  1. void register_epoll_handler(int fd, void (*fn)()) {  
  2.     epoll_event ev;  
  3.     ev.events = EPOLLIN;  
  4.     ev.data.ptr = reinterpret_cast<void*>(fn);  
  5.     if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, fd, &ev) == -1) {  
  6.         ERROR("epoll_ctl failed: %s\n", strerror(errno));  
  7.     }  
  8. }  

先我们就来解析下handle_property_set_fd函数

[cpp]  view plain  copy
  1. static void handle_property_set_fd()  
  2. {  
  3.     prop_msg msg;  
  4.     int s;  
  5.     int r;  
  6.     struct ucred cr;  
  7.     struct sockaddr_un addr;  
  8.     socklen_t addr_size = sizeof(addr);  
  9.     socklen_t cr_size = sizeof(cr);  
  10.     char * source_ctx = NULL;  
  11.     struct pollfd ufds[1];  
  12.     const int timeout_ms = 2 * 1000;  /* Default 2 sec timeout for caller to send property. */  
  13.     int nr;  
  14.   
  15.     if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {//获取对端socket的fd  
  16.         return;  
  17.     }  
  18.   
  19.     /* Check socket options here */  
  20.     if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {  
  21.         close(s);  
  22.         ERROR("Unable to receive socket options\n");  
  23.         return;  
  24.     }  
  25.   
  26.     ufds[0].fd = s;  
  27.     ufds[0].events = POLLIN;  
  28.     ufds[0].revents = 0;  
  29.     nr = TEMP_FAILURE_RETRY(poll(ufds, 1, timeout_ms));  
  30.     if (nr == 0) {  
  31.         ERROR("sys_prop: timeout waiting for uid=%d to send property message.\n", cr.uid);  
  32.         close(s);  
  33.         return;  
  34.     } else if (nr < 0) {  
  35.         ERROR("sys_prop: error waiting for uid=%d to send property message: %s\n", cr.uid, strerror(errno));  
  36.         close(s);  
  37.         return;  
  38.     }  
  39.   
  40.     r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), MSG_DONTWAIT));//获取socket数据  
  41.     if(r != sizeof(prop_msg)) {  
  42.         ERROR("sys_prop: mis-match msg size received: %d expected: %zu: %s\n",  
  43.               r, sizeof(prop_msg), strerror(errno));  
  44.         close(s);  
  45.         return;  
  46.     }  
  47.   
  48.     switch(msg.cmd) {  
  49.     case PROP_MSG_SETPROP:  
  50.         msg.name[PROP_NAME_MAX-1] = 0;  
  51.         msg.value[PROP_VALUE_MAX-1] = 0;  
  52.   
  53.         if (!is_legal_property_name(msg.name, strlen(msg.name))) {  
  54.             ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);  
  55.             close(s);  
  56.             return;  
  57.         }  
  58.   
  59.         getpeercon(s, &source_ctx);  
  60.   
  61.         if(memcmp(msg.name,"ctl.",4) == 0) {//ctl类型  
  62.             // Keep the old close-socket-early behavior when handling  
  63.             // ctl.* properties.  
  64.             close(s);  
  65.             if (check_control_mac_perms(msg.value, source_ctx)) {  
  66.                 handle_control_message((char*) msg.name + 4, (char*) msg.value);  
  67.             } else {  
  68.                 ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",  
  69.                         msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);  
  70.             }  
  71.         } else {  
  72.             if (check_perms(msg.name, source_ctx)) {//检查权限  
  73.                 property_set((char*) msg.name, (char*) msg.value);//设置属性  
  74.             } else {  
  75.                 ERROR("sys_prop: permission denied uid:%d  name:%s\n",  
  76.                       cr.uid, msg.name);  
  77.             }  
  78.   
  79.             // Note: bionic's property client code assumes that the  
  80.             // property server will not close the socket until *AFTER*  
  81.             // the property is written to memory.  
  82.             close(s);  
  83.         }  
  84.         freecon(source_ctx);  
  85.         break;  
  86.   
  87.     default:  
  88.         close(s);  
  89.         break;  
  90.     }  
  91. }  

我们先来看看处理ctl类型的属性,ctl.start ctl.stop ctl.restart.

[cpp]  view plain  copy
  1. void handle_control_message(const char *msg, const char *arg)  
  2. {  
  3.     if (!strcmp(msg,"start")) {  
  4.         msg_start(arg);  
  5.     } else if (!strcmp(msg,"stop")) {  
  6.         msg_stop(arg);  
  7.     } else if (!strcmp(msg,"restart")) {  
  8.         msg_restart(arg);  
  9.     } else {  
  10.         ERROR("unknown control msg '%s'\n", msg);  
  11.     }  
  12. }  

最后调用了下面这三个函数来处理这些命令。总的是先看看有没有这个service,然后调用start stop 或者是restart相关函数。

[cpp]  view plain  copy
  1. static void msg_start(const char *name)  
  2. {  
  3.     struct service *svc = NULL;  
  4.     char *tmp = NULL;  
  5.     char *args = NULL;  
  6.   
  7.     if (!strchr(name, ':'))  
  8.         svc = service_find_by_name(name);  
  9.     else {  
  10.         tmp = strdup(name);  
  11.         if (tmp) {  
  12.             args = strchr(tmp, ':');  
  13.             *args = '\0';  
  14.             args++;  
  15.   
  16.             svc = service_find_by_name(tmp);  
  17.         }  
  18.     }  
  19.   
  20.     if (svc) {  
  21.         service_start(svc, args);  
  22.     } else {  
  23.         ERROR("no such service '%s'\n", name);  
  24.     }  
  25.     if (tmp)  
  26.         free(tmp);  
  27. }  
  28.   
  29. static void msg_stop(const char *name)  
  30. {  
  31.     struct service *svc = service_find_by_name(name);  
  32.   
  33.     if (svc) {  
  34.         service_stop(svc);  
  35.     } else {  
  36.         ERROR("no such service '%s'\n", name);  
  37.     }  
  38. }  
  39.   
  40. static void msg_restart(const char *name)  
  41. {  
  42.     struct service *svc = service_find_by_name(name);  
  43.   
  44.     if (svc) {  
  45.         service_restart(svc);  
  46.     } else {  
  47.         ERROR("no such service '%s'\n", name);  
  48.     }  
  49. }  

下面我们再来看property_set函数调用了property_set_impl函数来设置属性

[cpp]  view plain  copy
  1. int property_set(const char* name, const char* value) {  
  2.     int rc = property_set_impl(name, value);  
  3.     if (rc == -1) {  
  4.         ERROR("property_set(\"%s\", \"%s\") failed\n", name, value);  
  5.     }  
  6.     return rc;  
  7. }  
property_set_impl函数主要讲属性值写入,或者更新到共享内存中,然后当属性是net类型的,把net类型的属性名写入net.change属性,persist属性写入文件,最后调用property_changed函数来处理,属性改变后的触发器事件。

[cpp]  view plain  copy
  1. static int property_set_impl(const char* name, const char* value) {  
  2.     size_t namelen = strlen(name);  
  3.     size_t valuelen = strlen(value);  
  4.   
  5.     if (!is_legal_property_name(name, namelen)) return -1;  
  6.     if (valuelen >= PROP_VALUE_MAX) return -1;  
  7.   
  8.     if (strcmp("selinux.reload_policy", name) == 0 && strcmp("1", value) == 0) {  
  9.         if (selinux_reload_policy() != 0) {  
  10.             ERROR("Failed to reload policy\n");  
  11.         }  
  12.     } else if (strcmp("selinux.restorecon_recursive", name) == 0 && valuelen > 0) {  
  13.         if (restorecon_recursive(value) != 0) {  
  14.             ERROR("Failed to restorecon_recursive %s\n", value);  
  15.         }  
  16.     }  
  17.   
  18.     prop_info* pi = (prop_info*) __system_property_find(name);  
  19.   
  20.     if(pi != 0) {  
  21.         /* ro.* properties may NEVER be modified once set */  
  22.         if(!strncmp(name, "ro.", 3)) return -1;//ro文件,直接退出  
  23.   
  24.         __system_property_update(pi, value, valuelen);//更新属性数据到共享内存  
  25.     } else {  
  26.         int rc = __system_property_add(name, namelen, value, valuelen);//增加属性  
  27.         if (rc < 0) {  
  28.             return rc;  
  29.         }  
  30.     }  
  31.     /* If name starts with "net." treat as a DNS property. */  
  32.     if (strncmp("net.", name, strlen("net.")) == 0)  {  
  33.         if (strcmp("net.change", name) == 0) {  
  34.             return 0;  
  35.         }  
  36.        /* 
  37.         * The 'net.change' property is a special property used track when any 
  38.         * 'net.*' property name is updated. It is _ONLY_ updated here. Its value 
  39.         * contains the last updated 'net.*' property. 
  40.         */  
  41.         property_set("net.change", name);//net类型的属性,改变后需要写属性到net.change  
  42.     } else if (persistent_properties_loaded &&  
  43.             strncmp("persist.", name, strlen("persist.")) == 0) {  
  44.         /* 
  45.          * Don't write properties to disk until after we have read all default properties 
  46.          * to prevent them from being overwritten by default values. 
  47.          */  
  48.         write_persistent_property(name, value);//persist类型的属性写入到data/property目录下以属性名命名的文件  
  49.     }  
  50.     property_changed(name, value);  
  51.     return 0;  
  52. }  


我们先看下write_persistent_property函数,将属性在data/property目录下创建以属性名命名的文件,然后写入属性值。写入方式是先做了一个临时文件,成功后改名。

[cpp]  view plain  copy
  1. static void write_persistent_property(const char *name, const char *value)  
  2. {  
  3.     char tempPath[PATH_MAX];  
  4.     char path[PATH_MAX];  
  5.     int fd;  
  6.   
  7.     snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);  
  8.     fd = mkstemp(tempPath);//做临时文件  
  9.     if (fd < 0) {  
  10.         ERROR("Unable to write persistent property to temp file %s: %s\n", tempPath, strerror(errno));  
  11.         return;  
  12.     }  
  13.     write(fd, value, strlen(value));//写入数据  
  14.     fsync(fd);  
  15.     close(fd);  
  16.   
  17.     snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);  
  18.     if (rename(tempPath, path)) {//改名  
  19.         unlink(tempPath);  
  20.         ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path);  
  21.     }  
  22. }  

property_changed函数就是看有哪些满足属性的触发器,然后放入执行队列中。最后在init的循环中,执行触发器相应的命令

[cpp]  view plain  copy
  1. void property_changed(const char *name, const char *value)  
  2. {  
  3.     if (property_triggers_enabled)  
  4.         queue_property_triggers(name, value);  
  5. }  
[cpp]  view plain  copy
  1. void queue_property_triggers(const char *name, const char *value)  
  2. {  
  3.     struct listnode *node, *node2;  
  4.     struct action *act;  
  5.     struct trigger *cur_trigger;  
  6.     bool match;  
  7.     int name_length;  
  8.   
  9.     list_for_each(node, &action_list) {  
  10.         act = node_to_item(node, struct action, alist);  
  11.         match = !name;  
  12.         list_for_each(node2, &act->triggers) {  
  13.             cur_trigger = node_to_item(node2, struct trigger, nlist);  
  14.             if (!strncmp(cur_trigger->name, "property:", strlen("property:"))) {  
  15.                 const char *test = cur_trigger->name + strlen("property:");  
  16.                 if (!match) {  
  17.                     name_length = strlen(name);  
  18.                     if (!strncmp(name, test, name_length) &&  
  19.                         test[name_length] == '=' &&  
  20.                         (!strcmp(test + name_length + 1, value) ||  
  21.                         !strcmp(test + name_length + 1, "*"))) {  
  22.                         match = true;  
  23.                         continue;  
  24.                     }  
  25.                 }  
  26.                 const char* equals = strchr(test, '=');  
  27.                 if (equals) {  
  28.                     char prop_name[PROP_NAME_MAX + 1];  
  29.                     char value[PROP_VALUE_MAX];  
  30.                     int length = equals - test;  
  31.                     if (length <= PROP_NAME_MAX) {  
  32.                         int ret;  
  33.                         memcpy(prop_name, test, length);  
  34.                         prop_name[length] = 0;  
  35.   
  36.                         /* does the property exist, and match the trigger value? */  
  37.                         ret = property_get(prop_name, value);  
  38.                         if (ret > 0 && (!strcmp(equals + 1, value) ||  
  39.                                         !strcmp(equals + 1, "*"))) {  
  40.                             continue;  
  41.                         }  
  42.                     }  
  43.                 }  
  44.             }  
  45.             match = false;  
  46.             break;  
  47.         }  
  48.         if (match) {  
  49.             action_add_queue_tail(act);//最后将满足的触发器加入执行队列中  
  50.         }  
  51.     }  
  52. }  



3.3 读取文件中属性

我们先来看init.rc中的下面触发器

3.3.1 /system/build.prop
[cpp]  view plain  copy
  1. on load_system_props_action  
  2.     load_system_props  

而load_system_props_action是在late-init中触发的

[cpp]  view plain  copy
  1. on late-init  
  2.     trigger early-fs  
  3.     trigger fs  
  4.     trigger post-fs  
  5.   
  6.     # Load properties from /system/ + /factory after fs mount. Place  
  7.     # this in another action so that the load will be scheduled after the prior  
  8.     # issued fs triggers have completed.  
  9.     trigger load_system_props_action  

我们再来看load_system_props的处理,其中PROP_PATH_SYSTEM_BUILD就是/system/build.prop文件,load_properties_from_file函数最后会调用property_set函数设置属性

[cpp]  view plain  copy
  1. void load_system_props() {  
  2.     load_properties_from_file(PROP_PATH_SYSTEM_BUILD, NULL);  
  3.     load_properties_from_file(PROP_PATH_VENDOR_BUILD, NULL);  
  4.     load_properties_from_file(PROP_PATH_FACTORY, "ro.*");  
  5.     load_recovery_id_prop();  
  6. }  


3.3.2 /data/local.prop /data/property

同样persist类型的属性如下:

[cpp]  view plain  copy
  1. on load_persist_props_action  
  2.     load_persist_props  
  3.     start logd  
  4.     start logd-reinit  

也是在late-init触发,最后调用load_persist_props

[cpp]  view plain  copy
  1. on late-init  
  2.     trigger early-fs  
  3.     trigger fs  
  4.     trigger post-fs  
  5.   
  6.     # Load properties from /system/ + /factory after fs mount. Place  
  7.     # this in another action so that the load will be scheduled after the prior  
  8.     # issued fs triggers have completed.  
  9.     trigger load_system_props_action  
  10.   
  11.     # Now we can mount /data. File encryption requires keymaster to decrypt  
  12.     # /data, which in turn can only be loaded when system properties are present  
  13.     trigger post-fs-data  
  14.     trigger load_persist_props_action  

load_persist_props函数调用了load_override_properties load_persistent_properties来去读属性值

[cpp]  view plain  copy
  1. void load_persist_props(void) {  
  2.     load_override_properties();  
  3.     /* Read persistent properties after all default values have been loaded. */  
  4.     load_persistent_properties();//读取data/property/下面persist类型的属性  
  5. }  
load_override_properties函数,如果ro.debuggable为1.从文件/data/local.prop来读取属性。/data/local.prop文件时为了覆盖系统缺省的属性值。build.prop文件放在system目录下,修改不是很方便,如果希望测试某个属性,可以在/data/local.prop文件中修改,可以覆盖build.prop中的定义。
[cpp]  view plain  copy
  1. static void load_override_properties() {  
  2.     if (ALLOW_LOCAL_PROP_OVERRIDE) {  
  3.         char debuggable[PROP_VALUE_MAX];  
  4.         int ret = property_get("ro.debuggable", debuggable);  
  5.         if (ret && (strcmp(debuggable, "1") == 0)) {  
  6.             load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE, NULL);  
  7.         }  
  8.     }  
  9. }  
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值