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

作者:徐建祥([email protected])
日期:2009/11/11
网址:http://www.anymobile.org

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,   0666    0    0  );
44             if  (fd   <     0    return     -  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       }


OVER!

你可能感兴趣的:(properties)