AndroidSystemProperties设置取得系统属性的⽤法总结
通过调查得知,Android系统中取得/设置系统属性的⽤法参考以下3篇⽂章就⾜够了。
1.
介绍了设置属性需要的权限,已经设置权限的⽅法。
Systemproperties类在android.os下,但这个类是隐藏的,上层程序开发⽆法直接使⽤。其实⽤java的反射机制是可以使⽤这个类。何谓java反射机制,请⾃⾏研究学习,在此不做介绍,放到后续⽂章中。⽤JNI的⽅式,可以绕过Systemproperties这个类,直接本地调⽤来实现创建、获取及修改系统属性。在此也不做介绍,也放到后续⽂章中。
这篇⽂章主要介绍android系统属性的命名⽅式:
创建与修改android属性⽤Systemproperties.set(name, value),获取android属性⽤(name),需要注意的是android属性的名称是有⼀定的格式要求的,如下:前缀必须⽤system\core\init\property_service.c中定义的前缀,进⾏系统属性设置的程序也必须有system或root权限,
如何将android程序的权限提升到system权限?⽅法是这样的:
1、在l中,在manifest加⼊android:sharedUserId="android.uid.system"。
2、在Android.mk中,將LOCAL_CERTIFICATE := XXX修改成LOCAL_CERTIFICATE :=platform。
经过以上两步就可以把ap的权限提升到system权限了。但是⽤这种⽅法提升权限有两个弊端,如下:
1、程序的拥有都必须有程序的源码;
2、程序的拥有都还必须有android开发环境,就是说⾃⼰能make整个android系统。
⼀般能做这两点的,基本上都是开发⼈员!
2.
介绍了取得、设置系统权限的流程。
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的接⼝定义,
1private static native String native_get(String key);
2private static native String native_get(String key, String def);
3private static native void native_set(String key, String def);
4public static void set(String key, String val) {
5if (key.length() > PROP_NAME_MAX) {
6throw new IllegalArgumentException("key.length > "+ PROP_NAME_MAX);
7        }
8if (val !=null&& val.length() > PROP_VALUE_MAX) {
9throw 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
1namespace android {
2extern int register_android_os_SystemProperties(JNIEnv *env);
3    }
frameworks/base/core/jni/android_os_SystemProperties.cpp
1static void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ, jstring valJ)
2    {
3int err;
4const char* key;
5const char* val;
6        key = env->GetStringUTFChars(keyJ, NULL);
7if (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);
14if (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"
2struct {
3const char*prefix;
4        unsigned int uid;
5    } property_perms[] = {
6        { "0.",    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        { "",    AID_SHELL },
24        { "persist.sys.",    AID_SYSTEM },
25        { "persist.service.",  AID_SYSTEM },
26        { NULL, 0 }
27    };
28int property_set(const char*name, const char*value)
29    {
30        property_changed(name, value);
31return0;
32    }
33int start_property_service(void)
34    {
35int 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);
java系统变量设置
44if(fd <0) return-1;
45        fcntl(fd, F_SETFD, FD_CLOEXEC);
46        fcntl(fd, F_SETFL, O_NONBLOCK);
47
48        listen(fd, 8);
49return fd;
50    }
51void handle_property_set_fd(int fd)
52    {
d) {
54case PROP_MSG_SETPROP:
55            msg.name[PROP_NAME_MAX-1] =0;
56            msg.value[PROP_VALUE_MAX-1] =0;
57
58if(memcmp(msg.name,"ctl.",4) ==0) {
59if (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 {
66if (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            }
73break;
74
75default:
76break;
77        }
78    }
在开机启动后的init操作中,会执⾏⼀个loop循环,当检测到有新的设置时,进⼊设置流程,鉴权失败会提⽰相关的异常,如sys_prop: permission denied uid:1000  name:gsm.phone.id
system/core/init/init.c
1void property_changed(const char*name, const char*value)
2    {
3if (property_triggers_enabled) {
4            queue_property_triggers(name, value);
5            drain_action_queue();
6        }
7    }
8int main(int argc, char**argv)
9    {
10        parse_config_file("/");
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;
23for(;;) {
24if (ufds[0].revents == POLLIN)
25                handle_device_fd(device_fd);
26
27if (ufds[1].revents == POLLIN)
28                handle_property_set_fd(property_set_fd);
29if (ufds[3].revents == POLLIN)
30                handle_keychord(keychord_fd);
31        }
32return0;
33    }
3.
介绍了Android中三种⽅式来设置和获取属性。
Native代码中通过property_get/property_set来读取和设置属性。
属性(property)系统对Android来说是⼀个重要的功能。他作为⼀个系统服务管理着系统的配置和状态,所有的这些系统配置和状态都是属性(property)。属性(property)是⼀对键/值(key/value)组合,键和值都是字符串类型。总体感觉属性系统⾮常像Windows的注册表的功能。Androd中⾮常多的应⽤程序和库直接或者间接的依赖于属性系统,并由此决定其运⾏期的⾏为。例如:adbd进程通过属性来决定是否当前运⾏在模拟器中。再⽐如:⽅法返回存储在属性服务中的值。
属性系统怎样⼯作
属性系统宏观的结构图如下所⽰:
从图中我们可以看出Android属性系统由有三个进程,⼀组属性⽂件和⼀块共享内存组成。这块共享内存保存着系统中所有的属性记录,只有Property service能写这块共享内存,并且Property service负责将属性⽂件中的属性记录加载到共享内存中。
属性读取进程(property consumer)把这块共享内存映射到⾃⼰的进程空间,然后直接读取它。属性设置进程(property setter)也加载这块共享到他的进程空间,但是他不能直接写这块共享内存。当他需要
增加或者修改属性的时候,通过Unix Socket发⽣属性给Property service,Property service将代表设置进程写⼊共享内存和属性⽂件。
Property service运⾏于init进程中。init进程⾸先创建⼀块共享内存,并把他的句柄fd存放在这块内存中,init进程通过mmap带MAP_SHARE标志的系统调⽤,把这块内存映射到他的虚拟空间中,最终这块内存所有的更新将会被所有映射这块共享内存的进程看到。共享内存句柄fd和共享内存⼤⼩存储在系统环境变
量“ANDROID_PROPERTY_WORKSPACE”中,所有的进程包括属性设置进程和属性读取进程都将通过这个系统环境变量获得共享内存的句柄fd和⼤⼩,然后把这块内存映射到他们⾃⼰的虚拟空间。共享内存布局如下:
然后,init进程将会从以下⽂件中加载属性:
1: /default.prop
2: /system/build.prop
3: /system/default.prop
4: /data/local.prop
下⼀步是启动Property service。这步中,将会创建⼀个Unix Socket服务器,这个Socket有⼀个闻名的名
称“/dev/socket/property_service”。最后init进⼊死循环,等待socket的连接请求。
在读取进程中,当它初始化libc库的时候,将会获得属性系统共享内存的句柄和⼤⼩
(bionic/libc/bionic/libc_init_common.c __libc_init_common函数)。并把这块共享内存映射到⾃⼰的进程虚拟空间中(bionic/libc/bionic/system_properties.c __system_properties_init函数)。这样读取进程将会向访问普通内存⼀样访问属性系统的共享内存了。
当前,属性不能被删除。也就是说⼀旦属性被创建,将不可以被删除,但是它们可以被修改。
怎样获得和设置属性
在Android中有三种⽅式来设置和获取属性:
1、Native代码
当编写Native的程序时,可以使⽤property_get和property_set API来获得和设置属性。使⽤这两个API必须要包含头⽂件和链接libcutil库。
2、Java代码
Android在Java库中提供Property和System.setProperty⽅法,我们Java程序可以通过他们来设置和获得属性。
但是请注意!虽然从语法上⾯看Java的代码和Native代码⾮常相近,但是Java版本存储把属性存在其他地⽅,⽽不是我们上⾯提到的属性系统中。在JVM中有⼀个hash表来维护Java的属性。所以Java属性和Android属性是不同的,不能⽤Java API(Property和System.setProperty)来设置系统属性。也不能通过Native的⽅法(property_get 和property_set)设置Java的属性。
更新:指出android.os.SystemProperties可以操作Android系统属性(虽然这个类倾向于内部使⽤)。这个类通过JNI调⽤Native的property_get和property_set⽅法来获得和设置属性。
3、Shell脚本
Android提供了命令⾏⼯具setprop和getprop来设置和获取属性,他们可以在脚本中被使⽤。
补充:通过查看property_service.c,我们可以明确以下事实:
1、  属性名不是随意取的。在property_perms数组中定义了当前系统上可⽤的所有属性的前缀,以及相对应的存取权限UID。对属性的设置要满⾜权限要求,同时命名也要在这些定义的范围内。
2、  PA_COUNT_MAX指定了系统(共享内存区域中)最多能存储多少个属性。
3、  PROP_NAME_MAX指定了⼀个属性的key最⼤允许长度;PROP_VALUE_MAX则指定了value的最⼤允许长度。
property_get/property_set
每个属性都有⼀个名称和值,他们都是字符串格式。属性被⼤量使⽤在Android系统中,⽤来记录系统设置或进程之间的信息交换。属性是在整个系统中全局可见的。每个进程可以get/set属性。
在系统初始化时,Android将分配⼀个共享内存区来存储的属性。这些是由“init”守护进程完成的,其源代码位于:
device/system/init。“init”守护进程将启动⼀个属性服务。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。