当前位置:   article > 正文

Android4.4属性系统-属性设置_must use __system_property_read_callback() to read

must use __system_property_read_callback() to read

Android4.4属性系统-属性设置

原创:https://www.jianshu.com/p/945ff5476cf8

DD_Dog关注

2019.07.30 16:36:31字数 844阅读 81

一、Android4.4属性系统系列文章

Android4.4属性系统-初始化
Android4.4属性系统-系统服务
Android4.4属性系统-内存空间共享
Android4.4属性系统-属性获取
Android4.4属性系统-属性设置
Android4.4-属性的使用总结

二、写在前面-如何阅读本系列文章

本系列文章大部分是对源码的解析和注释,所以读起来枯燥无味,并且杂乱,这是阅读系统源码无法避免的,如果你有条件,可以点击下载Android4.4源码,阅读源码可以使用eclise,AndroidStudio,vim等。

文章的章节安卓是按照代码模块区分的,例如init进程代码,libcutils代码是按章节来区分,但不同模块的代码之间是有关联的,阅读时需要经常跳转,通过搜索功能进行页内搜索即可

三、属性设置

Android 除了提供属性获取函数外,当然还可以进行属性的设置操作,在 Java 层可以通过调用 SystemProperties.set(String key, String val)方法进行属性设置。

3.1 frameworks接口

源码路径frameworks/base/core/java/android/os/Build.java

  1. /**
  2. * Set the value for the given key.
  3. * @throws IllegalArgumentException if the key exceeds 32 characters
  4. * @throws IllegalArgumentException if the value exceeds 92 characters
  5. */
  6. public static void set(String key, String val) {
  7. if (key.length() > PROP_NAME_MAX) {
  8. throw new IllegalArgumentException("key.length > " + PROP_NAME_MAX);
  9. }
  10. if (val != null && val.length() > PROP_VALUE_MAX) {
  11. throw new IllegalArgumentException("val.length > " +
  12. PROP_VALUE_MAX);
  13. }
  14. native_set(key, val);
  15. }

首先对需要设置的属性的名称以及值做长度检查,再调用 Native函数native_set。native_set对应的C++层函数为SystemProperties_set(/frameworks/base/core/jni/android_os_SystemProperties.cpp)

3.2 JNI接口

源码 路径frameworks/base/core/jni/android_os_SystemProperties.cpp
JNI代码中,有方法映射表,native_get映射为SystemProperties_getS方法

  1. #include "cutils/properties.h"
  2. //方法映射表
  3. static JNINativeMethod method_table[] = {
  4. { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
  5. (void*) SystemProperties_getS },
  6. { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
  7. (void*) SystemProperties_getSS },
  8. { "native_get_int", "(Ljava/lang/String;I)I",
  9. (void*) SystemProperties_get_int },
  10. { "native_get_long", "(Ljava/lang/String;J)J",
  11. (void*) SystemProperties_get_long },
  12. { "native_get_boolean", "(Ljava/lang/String;Z)Z",
  13. (void*) SystemProperties_get_boolean },
  14. { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
  15. (void*) SystemProperties_set },
  16. { "native_add_change_callback", "()V",
  17. (void*) SystemProperties_add_change_callback },
  18. };
  19. //native_set方法对应SystemProperties_set
  20. static void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ, jstring valJ)
  21. {
  22. LOGD("SystemProperties_set,keyJ=%s,valJ=%s", keyJ, valJ);
  23. int err;
  24. const char* key;
  25. const char* val;
  26. if (keyJ == NULL) {
  27. jniThrowNullPointerException(env, "key must not be null.");
  28. return ;
  29. }
  30. //将jstring类型变成一个char *类型
  31. key = env->GetStringUTFChars(keyJ, NULL);
  32. if (valJ == NULL) {
  33. val = ""; /* NULL pointer not allowed here */
  34. } else {
  35. val = env->GetStringUTFChars(valJ, NULL);
  36. }
  37. //关键代码:调用property_set,在properties.c中实现
  38. err = property_set(key, val);
  39. //调用ReleaseStringUTFChars函数通知JVM这块内存已经不使用
  40. env->ReleaseStringUTFChars(keyJ, key);
  41. //一些错误处理
  42. if (valJ != NULL) {
  43. env->ReleaseStringUTFChars(valJ, val);
  44. }
  45. if (err < 0) {
  46. jniThrowException(env, "java/lang/RuntimeException",
  47. "failed to set system property");
  48. }
  49. }

调用了 property_set 函数,该函数统一定义在/system/core/libcutils/properties.c 文件中

3.3 libc库层

3.3.1 内核c库层

源码路径system/core/libcutils/properties.c

  1. #include <cutils/properties.h>
  2. //set方法,参数<key,value>
  3. int property_set(const char *key, const char *value)
  4. {
  5. ALOGV("property_set, key=%s,value=%s", key, value);
  6. //关键调用,位于bionic/libc/bionic/system_properties.c
  7. return __system_property_set(key, value);
  8. }

调用了__system_property_set 函数,该函数位于/bionic/libc/bionic/system_properties.c 文件

3.3.2 bionic库层

源码路径bionic/libc/bionic/system_properties.c
该函数通过__system_property_find 函数在系统属性内存区域查询是否存在 name 参数指定的属性,如果查询到则会通过__system_property_read 读取属性信息。关于__system_property_find函数,前文已经分析过了。__system_property_read 通过获取的内存地址,从内存中读取属性信息。

  1. //set方法
  2. int __system_property_set(const char *key, const char *value)
  3. {
  4. printf("__system_property_set--bianjb,key=%s,value=%s", key, value);
  5. int err;
  6. //prop_msg为要发送给服务端的消息句柄
  7. prop_msg msg;
  8. if(key == 0) return -1;
  9. if(value == 0) value = "";
  10. //判断key,value长度是否合法
  11. if(strlen(key) >= PROP_NAME_MAX) return -1;
  12. if(strlen(value) >= PROP_VALUE_MAX) return -1;
  13. memset(&msg, 0, sizeof msg); //初始化内存
  14. //设置Prop操作类型
  15. msg.cmd = PROP_MSG_SETPROP;
  16. //设置消息name字段
  17. strlcpy(msg.name, key, sizeof msg.name);
  18. //设置消息value字段
  19. strlcpy(msg.value, value, sizeof msg.value);
  20. //send_prop_msg 函数向属性系统服务的 socket发送属性设置请求信息
  21. err = send_prop_msg(&msg);
  22. if(err < 0) {
  23. return err;
  24. }
  25. return 0;
  26. }
  27. //发送消息
  28. static int send_prop_msg(prop_msg *msg)
  29. {
  30. struct pollfd pollfds[1];
  31. struct sockaddr_un addr;
  32. socklen_t alen;
  33. size_t namelen;
  34. int s;
  35. int r;
  36. int result = -1;
  37. s = socket(AF_LOCAL, SOCK_STREAM, 0);
  38. if(s < 0) {
  39. return result;
  40. }
  41. memset(&addr, 0, sizeof(addr));
  42. // property_service_socket 值为”/dev/socket/property_service”
  43. //正是前文分析 Android 属性系统服务所监听的 socket
  44. namelen = strlen(property_service_socket);
  45. strlcpy(addr.sun_path, property_service_socket, sizeof addr.sun_path);
  46. addr.sun_family = AF_LOCAL;
  47. alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
  48. //connect尝试连接这个服务端 socket
  49. if(TEMP_FAILURE_RETRY(connect(s, (struct sockaddr *) &addr, alen)) < 0) {
  50. close(s);
  51. return result;
  52. }
  53. //send向该 socket 发送消息
  54. r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));
  55. if(r == sizeof(prop_msg)) {
  56. //我们成功写入了属性服务器,但现在我们等待属性服务器完成其工作。它通过关闭套接字来确认它的完成,所以我们在这里
  57. //轮询(什么都没有),等待套接字关闭。如果你'adb shell setprop foo bar',你会在套接字关闭后看到POLLHUP。出于偏
  58. //执,我们将调查结果限制在250毫秒。
  59. pollfds[0].fd = s;
  60. pollfds[0].events = 0;
  61. r = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
  62. if (r == 1 && (pollfds[0].revents & POLLHUP) != 0) {
  63. result = 0;
  64. } else {
  65. //忽略超时并将其视为成功。 init进程是单线程的,它的属性服务有时响应很慢(可能是关闭启动子进程或其他东西),因此
  66. //这时超时并且调用者认为它失败了,即使它仍然可以解决它。所以我们在这里伪造它,主要是为了ctl.*属性,但是我们尝
  67. //试等待250毫秒,因此大多数时候执行read-after-write的调用者可以可靠地看到他们写的内容。
  68. result = 0;
  69. }
  70. }
  71. close(s);
  72. return result;
  73. }

prop_msg消息结构体定义在bionic/libc/include/sys/_system_properties.h,源码如下:

  1. #define PROP_MSG_SETPROP 1
  2. struct prop_msg
  3. {
  4. unsigned cmd;
  5. char name[PROP_NAME_MAX];
  6. char value[PROP_VALUE_MAX];
  7. };

上面的分析完成了向socket服务器发送请求消息的过程,那么服务器端是如何接收并处理的呢。

3.3 socket服务端接收请求消息并处理

在 init.c 文件中 main 函数的无限 for 循环中有对上述 socket 事件的处理,关键代码如下
源码位置system/core/init/init.c

  1. int main(int argc, char **argv)
  2. {
  3. ....
  4. for(;;) {
  5. int nr, i, timeout = -1;
  6. execute_one_command();
  7. restart_processes();
  8. //设置需要监听的 socket 文件描述符以及 socket 请求的事件
  9. if (!property_set_fd_init && get_property_set_fd() > 0) {
  10. ufds[fd_count].fd = get_property_set_fd();
  11. ufds[fd_count].events = POLLIN;
  12. ufds[fd_count].revents = 0;
  13. fd_count++;
  14. property_set_fd_init = 1;
  15. }
  16. ....
  17. //调用 poll 检查是否有期望的 soket 事件发生
  18. nr = poll(ufds, fd_count, timeout);
  19. if (nr <= 0)
  20. continue;
  21. for (i = 0; i < fd_count; i++) {
  22. if (ufds[i].revents == POLLIN) { //两个if判断所发生的的 socket 事件是否是来自于属性服务的socket
  23. if (ufds[i].fd == get_property_set_fd())
  24. handle_property_set_fd(); //处理相应的 socket 请求,定义在property_service.c
  25. else if (ufds[i].fd == get_keychord_fd())
  26. handle_keychord();
  27. else if (ufds[i].fd == get_signal_fd())
  28. handle_signal();
  29. }
  30. }
  31. }
  32. //处理控制消息,handle_control_message 根据属性名称来启动、停止或者重启服务
  33. void handle_control_message(const char *msg, const char *arg)
  34. {
  35. if (!strcmp(msg,"start")) {
  36. msg_start(arg);
  37. } else if (!strcmp(msg,"stop")) {
  38. msg_stop(arg);
  39. } else if (!strcmp(msg,"restart")) {
  40. msg_restart(arg);
  41. } else {
  42. ERROR("unknown control msg '%s'\n", msg);
  43. }
  44. }
  45. //prop发生改变
  46. void property_changed(const char *name, const char *value)
  47. {
  48. if (property_triggers_enabled) //是否开启了prop触发器
  49. queue_property_triggers(name, value);
  50. }
  51. static int queue_property_triggers_action(int nargs, char **args)
  52. {
  53. queue_all_property_triggers(); //定义在init_parser.c
  54. /* enable property triggers */
  55. property_triggers_enabled = 1;
  56. return 0;
  57. }

源码路径system/core/init/init_parser.c

  1. void queue_all_property_triggers()
  2. {
  3. struct listnode *node;
  4. struct action *act;
  5. list_for_each(node, &action_list) {
  6. act = node_to_item(node, struct action, alist);
  7. if (!strncmp(act->name, "property:", strlen("property:"))) {
  8. /* parse property name and value
  9. syntax is property:<name>=<value> */
  10. const char* name = act->name + strlen("property:");
  11. const char* equals = strchr(name, '=');
  12. if (equals) {
  13. char prop_name[PROP_NAME_MAX + 1];
  14. char value[PROP_VALUE_MAX];
  15. int length = equals - name;
  16. if (length > PROP_NAME_MAX) {
  17. ERROR("property name too long in trigger %s", act->name);
  18. } else {
  19. memcpy(prop_name, name, length);
  20. prop_name[length] = 0;
  21. /* does the property exist, and match the trigger value? */
  22. property_get(prop_name, value);
  23. if (!strcmp(equals + 1, value) ||!strcmp(equals + 1, "*")) {
  24. action_add_queue_tail(act);
  25. }
  26. }
  27. }
  28. }
  29. }
  30. }

源码路径system/core/init/property_service.c

  1. //处理客户端的连接请求
  2. void handle_property_set_fd()
  3. {
  4. prop_msg msg;
  5. int s;
  6. int r;
  7. int res;
  8. struct ucred cr;
  9. struct sockaddr_un addr;
  10. socklen_t addr_size = sizeof(addr);
  11. socklen_t cr_size = sizeof(cr);
  12. char * source_ctx = NULL;
  13. //accept接受连接请求
  14. if ((s = accept(property_set_fd, (struct sockaddr *) &addr, &addr_size)) < 0) {
  15. return;
  16. }
  17. /* Check socket options here */
  18. if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
  19. close(s);
  20. ERROR("Unable to receive socket options\n");
  21. return;
  22. }
  23. //recv从 socket 中获取数据,由于 send_prop_msg 发送的数据位 prop_msg,因此此处获得的数据便是一个 prop_msg 结构体
  24. r = TEMP_FAILURE_RETRY(recv(s, &msg, sizeof(msg), 0));
  25. if(r != sizeof(prop_msg)) {
  26. ERROR("sys_prop: mis-match msg size received: %d expected: %d errno: %d\n",
  27. r, sizeof(prop_msg), errno);
  28. close(s);
  29. return;
  30. }
  31. //根据 prop_msg 成员cmd 值做相应操作,对于属性设置请求来说,cmd 值为 PROP_MSG_SETPROP,而实际上
  32. //handle_property_set_fd 函数也只是处理属性设置请求
  33. switch(msg.cmd) {
  34. case PROP_MSG_SETPROP:
  35. msg.name[PROP_NAME_MAX-1] = 0;
  36. msg.value[PROP_VALUE_MAX-1] = 0;
  37. if (!is_legal_property_name(msg.name, strlen(msg.name))) {
  38. ERROR("sys_prop: illegal property name. Got: \"%s\"\n", msg.name);
  39. close(s);
  40. return;
  41. }
  42. getpeercon(s, &source_ctx);
  43. /*判断需要设置的属性名称是否以”ctl.”开头,
  44. *ctl.start 可以用来启动服务,
  45. *ctl.stop 用来停止服务,
  46. *ctl.restart 可以用来重启服务
  47. */
  48. if(memcmp(msg.name,"ctl.",4) == 0) {
  49. // Keep the old close-socket-early behavior when handling ctl.* properties.
  50. close(s);
  51. //检查控制权限,通过后就可以控制属性服务的启动和停止
  52. if (check_control_perms(msg.value, cr.uid, cr.gid, source_ctx)) {
  53. //处理控制消息
  54. handle_control_message((char*) msg.name + 4, (char*) msg.value);
  55. } else {
  56. ERROR("sys_prop: Unable to %s service ctl [%s] uid:%d gid:%d pid:%d\n",
  57. msg.name + 4, msg.value, cr.uid, cr.gid, cr.pid);
  58. }
  59. } else {
  60. //如果不是控制指令,检查权限
  61. if (check_perms(msg.name, cr.uid, cr.gid, source_ctx)) {
  62. property_set((char*) msg.name, (char*) msg.value);
  63. } else {
  64. ERROR("sys_prop: permission denied uid:%d name:%s\n",
  65. cr.uid, msg.name);
  66. }
  67. // Note: bionic's property client code assumes that the
  68. // property server will not close the socket until *AFTER*
  69. // the property is written to memory.
  70. close(s);
  71. }
  72. freecon(source_ctx);
  73. break;
  74. default:
  75. close(s);
  76. break;
  77. }
  78. }
  79. /* 白名单一
  80. * White list of UID that are allowed to start/stop services.
  81. * Currently there are no user apps that require.
  82. */
  83. struct {
  84. const char *service;
  85. unsigned int uid;
  86. unsigned int gid;
  87. } control_perms[] = {
  88. { "dumpstate",AID_SHELL, AID_LOG },
  89. { "ril-daemon",AID_RADIO, AID_RADIO },
  90. {NULL, 0, 0 }
  91. };
  92. /*
  93. * Checks permissions for starting/stoping system services.
  94. * AID_SYSTEM and AID_ROOT are always allowed.
  95. *
  96. * Returns 1 if uid allowed, 0 otherwise.
  97. *权限检查的基本思路是:若进程的 uid 属于 system 或者 root,则通过;若进程在 control_perms
  98. *白名单中,也可以通过检查,但是目前为止,没有用户应用程序存在于该白名单中。因此只
  99. *有具有 system 或者 root 权限才可以启动、停止以及重启服务。
  100. */
  101. static int check_control_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx) {
  102. int i;
  103. if (uid == AID_SYSTEM || uid == AID_ROOT)
  104. return check_control_mac_perms(name, sctx);
  105. /* Search the ACL */
  106. for (i = 0; control_perms[i].service; i++) {
  107. if (strcmp(control_perms[i].service, name) == 0) {
  108. if ((uid && control_perms[i].uid == uid) ||
  109. (gid && control_perms[i].gid == gid)) {
  110. return check_control_mac_perms(name, sctx);
  111. }
  112. }
  113. }
  114. return 0;
  115. }
  116. //白名单二,AID定义在`system/core/include/private/android_filesystem_config.h`
  117. /* White list of permissions for setting property services. */
  118. struct {
  119. const char *prefix;
  120. unsigned int uid;
  121. unsigned int gid;
  122. } property_perms[] = {
  123. { "net.rmnet0.", AID_RADIO, 0 },
  124. { "net.gprs.", AID_RADIO, 0 },
  125. { "net.ppp", AID_RADIO, 0 },
  126. { "net.qmi", AID_RADIO, 0 },
  127. { "net.lte", AID_RADIO, 0 },
  128. { "net.cdma", AID_RADIO, 0 },
  129. { "ril.", AID_RADIO, 0 },
  130. { "gsm.", AID_RADIO, 0 },
  131. { "persist.radio", AID_RADIO, 0 },
  132. { "persist.radio", AID_SYSTEM, 0 },
  133. { "net.dns", AID_RADIO, 0 },
  134. { "sys.usb.config", AID_RADIO, 0 },
  135. { "net.", AID_SYSTEM, 0 },
  136. { "dev.", AID_SYSTEM, 0 },
  137. { "runtime.", AID_SYSTEM, 0 },
  138. { "hw.", AID_SYSTEM, 0 },
  139. { "sys.", AID_SYSTEM, 0 },
  140. { "sys.powerctl", AID_SHELL, 0 },
  141. { "service.", AID_SYSTEM, 0 },
  142. { "wlan.", AID_SYSTEM, 0 },
  143. { "bluetooth.", AID_BLUETOOTH, 0 },
  144. { "dhcp.", AID_SYSTEM, 0 },
  145. { "dhcp.", AID_DHCP, 0 },
  146. { "debug.", AID_SYSTEM, 0 },
  147. { "debug.", AID_SHELL, 0 },
  148. { "log.", AID_SHELL, 0 },
  149. { "service.adb.root", AID_SHELL, 0 },
  150. { "service.adb.tcp.port", AID_SHELL, 0 },
  151. { "persist.sys.", AID_SYSTEM, 0 },
  152. { "persist.msms.", AID_RADIO, 0 },//SPRD: add for dsds
  153. { "persist.msms.", AID_SYSTEM, 0 },
  154. { "persist.service.", AID_SYSTEM, 0 },
  155. { "persist.security.", AID_SYSTEM, 0 },
  156. { "media.", AID_MEDIA, 0 },
  157. { "persist.service.bdroid.", AID_BLUETOOTH, 0 },
  158. { "selinux." , AID_SYSTEM, 0 },
  159. { "persist.modem.", AID_RADIO, 0 },//SPRD: add for lte
  160. { NULL, 0, 0 }
  161. };
  162. /*
  163. * Checks permissions for setting system properties.
  164. * Returns 1 if uid allowed, 0 otherwise.
  165. */
  166. static int check_perms(const char *name, unsigned int uid, unsigned int gid, char *sctx)
  167. {
  168. int i;
  169. unsigned int app_id;
  170. if(!strncmp(name, "ro.", 3))
  171. name +=3;
  172. //断是否具有 root 权限,若有通过检查
  173. if (uid == 0)
  174. return check_mac_perms(name, sctx);
  175. app_id = multiuser_get_app_id(uid);
  176. if (app_id == AID_BLUETOOTH) {
  177. uid = app_id;
  178. }
  179. //与 check_control_perms 一样,property_perms 也是一个可以进行属性设置的白名单。若通过权限检查,则会调用
  180. //property_set来进行属性设置操作,该函数在前文已有分析,此处略去
  181. for (i = 0; property_perms[i].prefix; i++) {
  182. if (strncmp(property_perms[i].prefix, name,
  183. strlen(property_perms[i].prefix)) == 0) {
  184. if ((uid && property_perms[i].uid == uid) ||
  185. (gid && property_perms[i].gid == gid)) {
  186. return check_mac_perms(name, sctx);
  187. }
  188. }
  189. }
  190. }
  191. return 0;
  192. }
  193. //最终真正的设置属性的函数
  194. int property_set(const char *name, const char *value)
  195. {
  196. prop_info *pi;
  197. int ret;
  198. size_t namelen = strlen(name); //计算key长度值
  199. size_t valuelen = strlen(value); //计算value长度值
  200. if (!is_legal_property_name(name, namelen)) return -1; //判断prop name是否合法
  201. if (valuelen >= PROP_VALUE_MAX) return -1;
  202. pi = (prop_info*) __system_property_find(name); //获取系统中的prop
  203. if(pi != 0) { //如果已经存在该prop
  204. /* ro.* properties may NEVER be modified once set */
  205. if(!strncmp(name, "ro.", 3)) return -1; //ro.开头的不允许修改,read only
  206. __system_property_update(pi, value, valuelen); //更新prop
  207. } else { //如果不存在,则添加
  208. ret = __system_property_add(name, namelen, value, valuelen); //添加prop
  209. if (ret < 0) {
  210. ERROR("Failed to set '%s'='%s'\n", name, value);
  211. return ret;
  212. }
  213. }
  214. /* If name starts with "net." treat as a DNS property. */
  215. //如果key是以net.开关的,当作DNS属性处理
  216. if (strncmp("net.", name, strlen("net.")) == 0) {
  217. if (strcmp("net.change", name) == 0) { //如果是net.change属性,直接返回
  218. return 0;
  219. }
  220. /*
  221. * The 'net.change' property is a special property used track when any
  222. * 'net.*' property name is updated. It is _ONLY_ updated here. Its value
  223. * contains the last updated 'net.*' property.
  224. */
  225. //'net.change'属性是一个特殊属性,用于跟踪任何'net.*'属性名称的更新。它只能在这里被更新。
  226. //其值包含最后更新的'net.*'属性。
  227. property_set("net.change", name);
  228. } else if (persistent_properties_loaded &&strncmp("persist.", name, strlen("persist.")) == 0) {
  229. /*
  230. * Don't write properties to disk until after we have read all default properties
  231. * to prevent them from being overwritten by default values.
  232. */
  233. //如果持久化属性已经加载完毕并且属性以persist.开头
  234. write_persistent_property(name, value);
  235. } else if (strcmp("selinux.reload_policy", name) == 0 && strcmp("1", value) == 0) {
  236. //如果是selinux.reload_policy=1
  237. selinux_reload_policy();
  238. }
  239. property_changed(name, value); //prop改变,发出通知,定义在init.c中
  240. return 0;
  241. }
  242. //判断prop name是否含有非法字符
  243. static bool is_legal_property_name(const char* name, size_t namelen)
  244. {
  245. size_t i;
  246. bool previous_was_dot = false;
  247. if (namelen >= PROP_NAME_MAX) return false; //超过最大长度,非法
  248. if (namelen < 1) return false; //长度小于1非法
  249. if (name[0] == '.') return false; //以'.'开头,非法
  250. if (name[namelen - 1] == '.') return false; //以'.'结尾,非法
  251. /* Only allow alphanumeric, plus '.', '-', or '_' */
  252. /* Don't allow ".." to appear in a property name */
  253. //只允许字母和数字,以及'.' '-' '_',并且不允许”..“
  254. for (i = 0; i < namelen; i++) {
  255. if (name[i] == '.') {
  256. if (previous_was_dot == true) return false;
  257. previous_was_dot = true;
  258. continue;
  259. }
  260. previous_was_dot = false;
  261. if (name[i] == '_' || name[i] == '-') continue;
  262. if (name[i] >= 'a' && name[i] <= 'z') continue;
  263. if (name[i] >= 'A' && name[i] <= 'Z') continue;
  264. if (name[i] >= '0' && name[i] <= '9') continue;
  265. return false;
  266. }
  267. return true;
  268. }
  269. //写入持久化prop,persist类型的prop要生成对应的文件,路径为/data/property
  270. static void write_persistent_property(const char *name, const char *value)
  271. {
  272. char tempPath[PATH_MAX];
  273. char path[PATH_MAX];
  274. int fd;
  275. snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
  276. fd = mkstemp(tempPath); //建立 临时文件
  277. if (fd < 0) {
  278. ERROR("Unable to write persistent property to temp file %s errno: %d\n", tempPath, errno);
  279. return;
  280. }
  281. write(fd, value, strlen(value));
  282. close(fd);
  283. snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
  284. if (rename(tempPath, path)) {
  285. unlink(tempPath);
  286. ERROR("Unable to rename persistent property file %s to %s\n", tempPath, path);
  287. }
  288. }

可以看到property_set函数又调用了__system_property_update,__system_property_add等函数,它们定义在
bionic/libc/bionic/system_properties.c
源码如下:

  1. //更新属性
  2. int __system_property_update(prop_info *pi, const char *value, unsigned int len)
  3. {
  4. prop_area *pa = __system_property_area__; //获取静态成员__system_property_area__,拿到共享内存区的地址
  5. if (len >= PROP_VALUE_MAX)
  6. return -1;
  7. //prop_info->serial,其高8位表示该prop_info中name的长度,而低24位表示该prop_info被更新的次数
  8. pi->serial = pi->serial | 1;
  9. ANDROID_MEMBAR_FULL();
  10. memcpy(pi->value, value, len + 1); //赋值value
  11. ANDROID_MEMBAR_FULL();
  12. pi->serial = (len << 24) | ((pi->serial + 1) & 0xffffff);
  13. __futex_wake(&pi->serial, INT32_MAX);
  14. pa->serial++; //访问次数加+,pa->serial表示该属性访问次数
  15. __futex_wake(&pa->serial, INT32_MAX);
  16. return 0;
  17. }
  18. //添加prop
  19. int __system_property_add(const char *name, unsigned int namelen,
  20. const char *value, unsigned int valuelen)
  21. {
  22. prop_area *pa = __system_property_area__;
  23. const prop_info *pi;
  24. if (namelen >= PROP_NAME_MAX) //检查name长度
  25. return -1;
  26. if (valuelen >= PROP_VALUE_MAX) //检查value长度
  27. return -1;
  28. if (namelen < 1)
  29. return -1;
  30. //查询prop应该存储的内存位置
  31. pi = find_property(root_node(), name, namelen, value, valuelen, true);
  32. if (!pi)
  33. return -1;
  34. pa->serial++; //访问次数加+,pa->serial表示该属性访问次数
  35. __futex_wake(&pa->serial, INT32_MAX);
  36. return 0;
  37. }
  38. //前面介绍过了,属性的存储结构为特里结构+二叉树结构,所以查找属性其实就是
  39. //特里结构+二叉树结构的遍历
  40. static const prop_info *find_property(prop_bt *trie, const char *name,
  41. uint8_t namelen, const char *value, uint8_t valuelen,
  42. bool alloc_if_needed)
  43. {
  44. const char *remaining_name = name;
  45. while (true) {
  46. char *sep = strchr(remaining_name, '.');
  47. bool want_subtree = (sep != NULL);
  48. uint8_t substr_size;
  49. prop_bt *root;
  50. if (want_subtree) {
  51. substr_size = sep - remaining_name;
  52. } else {
  53. substr_size = strlen(remaining_name);
  54. }
  55. if (!substr_size)
  56. return NULL;
  57. if (trie->children) {
  58. root = to_prop_obj(trie->children);
  59. } else if (alloc_if_needed) {
  60. root = new_prop_bt(remaining_name, substr_size, &trie->children);
  61. } else {
  62. root = NULL;
  63. }
  64. if (!root)
  65. return NULL;
  66. trie = find_prop_bt(root, remaining_name, substr_size, alloc_if_needed);
  67. if (!trie)
  68. return NULL;
  69. if (!want_subtree)
  70. break;
  71. remaining_name = sep + 1;
  72. }
  73. if (trie->prop) {
  74. return to_prop_obj(trie->prop);
  75. } else if (alloc_if_needed) {
  76. return new_prop_info(name, namelen, value, valuelen, &trie->prop);
  77. } else {
  78. return NULL;
  79. }
  80. }

AID用户定义
system/core/include/private/android_filesystem_config.h

  1. /* This is the master Users and Groups config for the platform.
  2. * DO NOT EVER RENUMBER
  3. */
  4. #define AID_ROOT 0 /* traditional unix root user */
  5. #define AID_SYSTEM 1000 /* system server */
  6. #define AID_RADIO 1001 /* telephony subsystem, RIL */
  7. #define AID_BLUETOOTH 1002 /* bluetooth subsystem */
  8. #define AID_GRAPHICS 1003 /* graphics devices */
  9. #define AID_INPUT 1004 /* input devices */
  10. #define AID_AUDIO 1005 /* audio devices */
  11. #define AID_CAMERA 1006 /* camera devices */
  12. #define AID_LOG 1007 /* log devices */
  13. #define AID_COMPASS 1008 /* compass device */
  14. #define AID_MOUNT 1009 /* mountd socket */
  15. #define AID_WIFI 1010 /* wifi subsystem */
  16. #define AID_ADB 1011 /* android debug bridge (adbd) */
  17. #define AID_INSTALL 1012 /* group for installing packages */
  18. #define AID_MEDIA 1013 /* mediaserver process */
  19. #define AID_DHCP 1014 /* dhcp client */
  20. #define AID_SDCARD_RW 1015 /* external storage write access */
  21. #define AID_VPN 1016 /* vpn system */
  22. #define AID_KEYSTORE 1017 /* keystore subsystem */
  23. #define AID_USB 1018 /* USB devices */
  24. #define AID_DRM 1019 /* DRM server */
  25. #define AID_MDNSR 1020 /* MulticastDNSResponder (service discovery) */
  26. #define AID_GPS 1021 /* GPS daemon */
  27. #define AID_UNUSED1 1022 /* deprecated, DO NOT USE */
  28. #define AID_MEDIA_RW 1023 /* internal media storage write access */
  29. #define AID_MTP 1024 /* MTP USB driver access */
  30. #define AID_UNUSED2 1025 /* deprecated, DO NOT USE */
  31. #define AID_DRMRPC 1026 /* group for drm rpc */
  32. #define AID_NFC 1027 /* nfc subsystem */
  33. #define AID_SDCARD_R 1028 /* external storage read access */
  34. #define AID_CLAT 1029 /* clat part of nat464 */
  35. #define AID_LOOP_RADIO 1030 /* loop radio devices */
  36. #define AID_MEDIA_DRM 1031 /* MediaDrm plugins */
  37. #define AID_PACKAGE_INFO 1032 /* access to installed package details */
  38. #define AID_SDCARD_PICS 1033 /* external storage photos access */
  39. #define AID_SDCARD_AV 1034 /* external storage audio/video access */
  40. #define AID_SDCARD_ALL 1035 /* access all users external storage */
  41. /* SPRD: add for storage manager @{ */
  42. #define AID_INTERNAL_WR 1051 /* write permission for internal storage */
  43. #define AID_EXTERNAL_WR 1052 /* write permission for external storage */
  44. /* @} */
  45. #define AID_SHELL 2000 /* adb and debug shell user */
  46. #define AID_CACHE 2001 /* cache access */
  47. #define AID_DIAG 2002 /* access to diagnostic resources */
  48. /* The 3000 series are intended for use as supplemental group id's only.
  49. * They indicate special Android capabilities that the kernel is aware of. */
  50. #define AID_NET_BT_ADMIN 3001 /* bluetooth: create any socket */
  51. #define AID_NET_BT 3002 /* bluetooth: create sco, rfcomm or l2cap sockets */
  52. #define AID_INET 3003 /* can create AF_INET and AF_INET6 sockets */
  53. #define AID_NET_RAW 3004 /* can create raw INET sockets */
  54. #define AID_NET_ADMIN 3005 /* can configure interfaces and routing tables. */
  55. #define AID_NET_BW_STATS 3006 /* read bandwidth statistics */
  56. #define AID_NET_BW_ACCT 3007 /* change bandwidth statistics accounting */
  57. #define AID_NET_BT_STACK 3008 /* bluetooth: access config files */
  58. #define AID_THEME 9001 /* SPRD: add for theme setting */
  59. #define AID_MISC 9998 /* access to misc storage */
  60. #define AID_NOBODY 9999
  61. #define AID_APP 10000 /* first app user */
  62. #define AID_ISOLATED_START 99000 /* start of uids for fully isolated sandboxed processes */
  63. #define AID_ISOLATED_END 99999 /* end of uids for fully isolated sandboxed processes */
  64. #define AID_USER 100000 /* offset for uid ranges for each user */
  65. #define AID_SHARED_GID_START 50000 /* start of gids for apps in each user to share */
  66. #define AID_SHARED_GID_END 59999 /* start of gids for apps in each user to share */

需要重点关注的几个:

  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_USER 100000 /* offset for uid ranges for each user */
  5. #define AID_USER 100000 /* offset for uid ranges for each user */

通过上述分析可知,Android 属性设置最终需要通过 init 进程完成,同时还有严格的权限检查,一般用户进程无法对 Android 属性进行设置。

四、上图

属性设置.png

五、参考

Android属性系统
Linux 内存映射函数 mmap
trie-特里结构
Linux 内存映射函数 mmap()函数详解

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/265032
推荐阅读
相关标签
  

闽ICP备14008679号