android 屬性系統,SystemProperties 的簡介---轉載

每一個屬性都有一個名稱和值,他們都是字符串格式。屬性被大量使用在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中。 html

 特別屬性
若是屬性名稱以「ro.」開頭,那麼這個屬性被視爲只讀屬性。一旦設置,屬性值不能改變。
若是屬性名稱以「persist.」開頭,當設置這個屬性時,其值也將寫入/data/property。
若是屬性名稱以「net.」開頭,當設置這個屬性時,「net.change」屬性將會自動設置,以加入到最後修改的屬性名。(這是很巧妙的。 netresolve模塊的使用這個屬性來追蹤在net.*屬性上的任何變化。)
屬性「 ctrl.start 」和「 ctrl.stop 」是用來啓動和中止服務。每一項服務必須在/init.rc中定義.系統啓動時,與init守護進程將解析init.rc和啓動屬性服務。一旦收到設置「 ctrl.start 」屬性的請求,屬性服務將使用該屬性值做爲服務名找到該服務,啓動該服務。這項服務的啓動結果將會放入「 init.svc.<服務名>「屬性中 。客戶端應用程序能夠輪詢那個屬性值,以肯定結果。 java

Android toolbox程序
Android toolbox程序提供了兩個工具: setprop和getprop獲取和設置屬性。其使用方法:
getprop <屬性名>
setprop <屬性名><<屬性值> android

Java
在Java應用程序可使用System.getProperty()和System.setProperty()函數獲取和設置屬性。 shell

Action
默認狀況下,設置屬性只會使"init"守護程序寫入共享內存,它不會執行任何腳本或二進制程序。可是,您能夠將您的想要的實現的操做與init.rc中某個屬性的變化相關聯.例如,在默認的init.rc中有: app

    # 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 socket

這樣,若是你設置persist.service.adb.enable爲1 ,"init"守護程序就知道須要採起行動:開啓adbd服務。 ionic

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

Ashmem是一個匿名共享內存(Anonymous SHared MEMory)系統,該系統增長了接口所以進程間能夠共享具名內存塊。舉一個例子,系統能夠利用Ashmem存儲圖標,當繪製用戶界面的時候多個進程也能夠訪問。Ashmem優於傳統Linux共享內存表如今當共享內存塊再也不被用的時候,它爲Kernel提供一種回收這些共享內存塊的手段。若是一個程序嘗試訪問Kernel釋放的一個共享內存塊,它將會收到一個錯誤提示,而後從新分配內存並重載數據。 工具

 


Android 的系統屬性包括兩部分:文件保存的持久屬性和每次開機導入的cache屬性。前者主要保存在下面幾個文件中:

bionic / libc / include / sys / _system_properties.h
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 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的接口定義,

<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->  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
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 1      namespace android {
2      extern  int register_android_os_SystemProperties(JNIEnv *env);
3     }

frameworks/base/core/jni/android_os_SystemProperties.cpp
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->  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
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> --> 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
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->  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
<!--<br /> <br /> Code highlighting produced by Actipro CodeHighlighter (freeware)<br /> http://www.CodeHighlighter.com/<br /> <br /> -->  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     }
相關文章
相關標籤/搜索