android 属性系统,SystemProperties 的简介

来源:互联网 发布:php连接mysql失败 编辑:程序博客网 时间:2024/05/21 09:24

      在android系统中,每个属性都有一个名称和值,他们都是字符串格式。属性被大量使用在Android系统中,用来记录系统设置或进程之间的信息交换。属性是在整个系统中全局可见的。每个进程可以get/set属性。
      在系统初始化时,Android将分配一个共享内存区来存储的属性。这些是由“init”守护进程完成的,其源代码位于:device/system/init。“init”守护进程将启动一个属性服务。属性服务在“init”守护进程中运行。每一个客户端想要设置属性时,必须连接属性服务,再向其发送信息。属性服务将会在共享内存区中修改和创建属性。任何客户端想获得属性信息,可以从共享内存直接读取。这提高了读取性能。
客户端应用程序可以调用libcutils中的API函数以GET/SET属性信息。libcutils的源代码位于:device/libs/cutils。API函数是:
int property_get(const char *key, char *value, const char *default_value);
int property_set(const char *key, const char *value);

而libcutils又调用libc中的 __system_property_xxx 函数获得共享内存中的属性。libc的源代码位于:device/system/bionic。
属性服务调用libc中的__system_property_init函数来初始化属性系统的共享内存。当启动属性服务时,将从以下文件中加载默认属性:
/ default.prop
/system/build.prop
/system/default.prop
/data/local.prop

属性将会以上述顺序加载。后加载的属性将覆盖原先的值。这些属性加载之后,最后加载的属性会被保持在/data/property中。

 特别属性:
如果属性名称以“ro.”开头,那么这个属性被视为只读属性。一旦设置,属性值不能改变。
如果属性名称以“persist.”开头,当设置这个属性时,其值也将写入/data/property。
如果属性名称以“net.”开头,当设置这个属性时,“net.change”属性将会自动设置,以加入到最后修改的属性名。(这是很巧妙的。 netresolve模块的使用这个属性来追踪在net.*属性上的任何变化。)
属性“ ctrl.start ”和“ ctrl.stop ”是用来启动和停止服务。每一项服务必须在/init.rc中定义.系统启动时,与init守护进程将解析init.rc和启动属性服务。一旦收到设置“ ctrl.start ”属性的请求,属性服务将使用该属性值作为服务名找到该服务,启动该服务。这项服务的启动结果将会放入“ init.svc.<服务名>“属性中 。客户端应用程序可以轮询那个属性值,以确定结果。

Android toolbox程序
Android toolbox程序提供了两个工具: setprop和getprop获取和设置属性。其使用方法:
getprop <属性名>
setprop <属性名><<属性值>

Java
在Java应用程序可以使用System.getProperty()和System.setProperty()函数获取和设置属性。

Action
默认情况下,设置属性只会使"init"守护程序写入共享内存,它不会执行任何脚本或二进制程序。但是,您可以将您的想要的实现的操作与init.rc中某个属性的变化相关联.例如,在默认的init.rc中有:

    # adbd on at boot in emulator
    on property:ro.kernel.qemu=1
       start adbd
    on property:persist.service.adb.enable=1
       start adbd
    on property:persist.service.adb.enable=0
       stop adbd

这样,如果你设置persist.service.adb.enable为1 ,"init"守护程序就知道需要采取行动:开启adbd服务。

文章中提到的共享内存就是Android特有的共享方式:ashmen

Ashmem是一个匿名共享内存(Anonymous SHared MEMory)系统,该系统增加了接口因此进程间可以共享具名内存块。举一个例子,系统可以利用Ashmem存储图标,当绘制用户界面的时候多个进程也可以访问。Ashmem优于传统Linux共享内存表现在当共享内存块不再被用的时候,它为Kernel提供一种回收这些共享内存块的手段。如果一个程序尝试访问Kernel释放的一个共享内存块,它将会收到一个错误提示,然后重新分配内存并重载数据。


Android 的系统属性(SystemProperties)设置分析

Android 的系统属性包括两部分:文件保存的持久属性和每次开机导入的cache属性。前者主要保存在下面几个文件中:

bionic/libc/include/sys/_system_properties.h

1     #define PROP_SERVICE_NAME "property_service"
2     #define PROP_PATH_RAMDISK_DEFAULT  "/default.prop"
3     #define PROP_PATH_SYSTEM_BUILD     "/system/build.prop"
4     #define PROP_PATH_SYSTEM_DEFAULT   "/system/default.prop"
5     #define PROP_PATH_LOCAL_OVERRIDE   "/data/local.prop"

后者则通过frameworks/base/core/java/android/os/SystemProperties.java的接口定义,

 1     private static native String native_get(String key);
 2     private static native String native_get(String key, String def);
 3     private static native void native_set(String key, String def);
 4     public static void set(String key, String val) {
 5         if (key.length() > PROP_NAME_MAX) {
 6             throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
 7         }
 8         if (val != null && val.length() > PROP_VALUE_MAX) {
 9             throw new IllegalArgumentException("val.length > " +
10                 PROP_VALUE_MAX);
11         }
12         native_set(key, val);
13     }

该接口类在初始化运行环境中注册对应的cpp接口android_os_SystemProperties.cpp,实际操作通过JNI调用的是cpp文件对应的接口:

frameworks/base/core/jni/AndroidRuntime.cpp
1     namespace android {
2     extern int register_android_os_SystemProperties(JNIEnv *env);
3     }

frameworks/base/core/jni/android_os_SystemProperties.cpp
 1     static void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ, jstring valJ)
 2     {
 3         int err;
 4         const char* key;
 5         const char* val;
 6         key = env->GetStringUTFChars(keyJ, NULL);
 7         if (valJ == NULL) {
 8             val = "";       /* NULL pointer not allowed here */
 9         } else {
10             val = env->GetStringUTFChars(valJ, NULL);
11         }
12         err = property_set(key, val);
13         env->ReleaseStringUTFChars(keyJ, key);        
14         if (valJ != NULL) {
15             env->ReleaseStringUTFChars(valJ, val);
16         }
17     }

设置key的value时,需要作鉴权,根据设置程序所在进程的fd获知uid值,比如system server进程可以设置net打头的key,不可以设置gsm打头的key,相关的定义如下:

system/core/include/private/android_filesystem_config.h
1     #define AID_ROOT             0  /* traditional unix root user */
2     #define AID_SYSTEM        1000  /* system server */
3     #define AID_RADIO         1001  /* telephony subsystem, RIL */
4     #define AID_DHCP          1014  /* dhcp client */
5     #define AID_SHELL         2000  /* adb and debug shell user */
6     #define AID_CACHE         2001  /* cache access */
7     #define AID_APP          10000 /* first app user */

system/core/init/property_service.c
 1     #define PERSISTENT_PROPERTY_DIR  "/data/property"
 2     struct {
 3         const char *prefix;
 4         unsigned int uid;
 5     } property_perms[] = {
 6         { "net.rmnet0.",    AID_RADIO },
 7         { "net.gprs.",      AID_RADIO },
 8         { "ril.",           AID_RADIO },
 9         { "gsm.",           AID_RADIO },
10         { "net.dns",        AID_RADIO },
11         { "net.usb0",       AID_RADIO },
12         { "net.",           AID_SYSTEM },
13         { "dev.",           AID_SYSTEM },
14         { "runtime.",       AID_SYSTEM },
15         { "hw.",            AID_SYSTEM },
16         { "sys.",        AID_SYSTEM },
17         { "service.",    AID_SYSTEM },
18         { "wlan.",        AID_SYSTEM },
19         { "dhcp.",        AID_SYSTEM },
20         { "dhcp.",        AID_DHCP },
21         { "debug.",        AID_SHELL },
22         { "log.",        AID_SHELL },
23         { "service.adb.root",    AID_SHELL },
24         { "persist.sys.",    AID_SYSTEM },
25         { "persist.service.",   AID_SYSTEM },
26         { NULL, 0 }
27     };
28     int property_set(const char *name, const char *value)
29     {
30         property_changed(name, value);
31         return 0;
32     }
33     int start_property_service(void)
34     {
35         int fd;
36 
37         load_properties_from_file(PROP_PATH_SYSTEM_BUILD);
38         load_properties_from_file(PROP_PATH_SYSTEM_DEFAULT);
39         load_properties_from_file(PROP_PATH_LOCAL_OVERRIDE);
40         /* Read persistent properties after all default values have been loaded. */
41         load_persistent_properties();
42 
43         fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM, 066600);
44         if(fd < 0return -1;
45         fcntl(fd, F_SETFD, FD_CLOEXEC);
46         fcntl(fd, F_SETFL, O_NONBLOCK);
47 
48         listen(fd, 8);
49         return fd;
50     }
51     void handle_property_set_fd(int fd)
52     {
53         switch(msg.cmd) {
54         case PROP_MSG_SETPROP:
55             msg.name[PROP_NAME_MAX-1= 0;
56             msg.value[PROP_VALUE_MAX-1= 0;
57 
58             if(memcmp(msg.name,"ctl.",4== 0) {
59                 if (check_control_perms(msg.value, cr.uid)) {
60                     handle_control_message((char*) msg.name + 4, (char*) msg.value);
61                 } else {
62                     ERROR("sys_prop: Unable to %s service ctl [%s] uid: %d pid:%d\n",
63                             msg.name + 4, msg.value, cr.uid, cr.pid);
64                 }
65             } else {
66                 if (check_perms(msg.name, cr.uid)) {
67                     property_set((char*) msg.name, (char*) msg.value);
68                 } else {
69                     ERROR("sys_prop: permission denied uid:%d  name:%s\n",
70                           cr.uid, msg.name);
71                 }
72             }
73             break;
74 
75         default:
76             break;
77         }
78     }

在开机启动后的init操作中,会执行一个loop循环,当检测到有新的设置时,进入设置流程,鉴权失败会提示相关的异常,如sys_prop: permission denied uid:1000  name:gsm.phone.id

system/core/init/init.c
 1     void property_changed(const char *name, const char *value)
 2     {
 3         if (property_triggers_enabled) {
 4             queue_property_triggers(name, value);
 5             drain_action_queue();
 6         }
 7     }
 8     int main(int argc, char **argv)
 9     {
10         parse_config_file("/init.rc");
11         qemu_init();
12         device_fd = device_init();
13         property_init();
14         fd = open(console_name, O_RDWR);
15         property_set_fd = start_property_service();
16         ufds[0].fd = device_fd;
17         ufds[0].events = POLLIN;
18         ufds[1].fd = property_set_fd;
19         ufds[1].events = POLLIN;
20         ufds[2].fd = signal_recv_fd;
21         ufds[2].events = POLLIN;
22         fd_count = 3;
23         for(;;) {
24             if (ufds[0].revents == POLLIN)
25                 handle_device_fd(device_fd);
26 
27             if (ufds[1].revents == POLLIN)
28                 handle_property_set_fd(property_set_fd);
29             if (ufds[3].revents == POLLIN)
30                 handle_keychord(keychord_fd);
31         }
32         return 0;
33     }


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 群里有低俗的人怎么办 老师不收礼物怎么办 发票跨年了怎么办 一用力就头疼怎么办 小孩天天玩游戏怎么办 手机分期人死了怎么办 人死了手机欠费怎么办 晚上想玩手机怎么办 孩子溺水后发烧怎么办 去台湾多次签证怎么办 怀孕不能玩手机怎么办 孕期天天玩手机怎么办 小孩子在家偷钱怎么办 小朋友被鸡抓伤怎么办 宝宝在学校不说怎么办? 宝宝不和小朋友玩怎么办 初中孩子不想上学怎么办 孩子装病不想上学怎么办 中学生叛逆不愿意上学怎么办 孩子去幼儿园哭闹怎么办 孩子哭闹不上学怎么办 孩子中班还哭怎么办 小孩子不爱上幼儿园怎么办 小孩子不爱去幼儿园怎么办 宝宝去幼儿园哭闹怎么办 宝宝上幼儿园哭闹怎么办 小朋友上幼儿园哭闹怎么办 迷路了怎么办幼儿故事 大班迷路了怎么办故事 玩手机眼睛干涩怎么办 宝睡觉不踏实怎么办 觉得自己老了怎么办 微信没自动扣费怎么办 东西放在家找不到怎么办 刚怀孕同房流产怎么办 开车遇上送葬的怎么办 流水钓鱼走漂怎么办 水库里小鱼太多怎么办 英国留学生怎么办澳签 老赖欠货款不还怎么办 老赖失信出国怎么办