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!

你可能感兴趣的:(Android,技术)