Android8.0.0-r4——Property Service的启动与初始化

Property Service的启动与初始化

init进程启动,分为两个阶段,阶段一主要是添加脚本执行环境,以及初始化必要的文件系统目录。接着通过execv来执行一个参数为--second-stage的新的init进程Image以取代之前的init进程Image。

阶段一请参考http://blog.csdn.net/nwpushuai/article/details/79346665

执行第二阶段的初始化时,开始初始化属性系统,主要分为以下几个步骤:        

    初始化属性共享内存;        

    加载系统默认属性值;        

    启动属性服务,监听属性修改请求命令;

    从磁盘中加载所有属性值到内存;

代码路径:/system/core/init/init.cpp (http://androidxref.com/8.0.0_r4/xref/system/core/init/init.cpp)

948int main(int argc, char** argv) {
949    if (!strcmp(basename(argv[0]), "ueventd")) {
950        return ueventd_main(argc, argv);
951    }
952
953    if (!strcmp(basename(argv[0]), "watchdogd")) {
954        return watchdogd_main(argc, argv);
955    }
956
957    if (REBOOT_BOOTLOADER_ON_PANIC) {
958        install_reboot_signal_handlers();
959    }
960
961    add_environment("PATH", _PATH_DEFPATH);
962
963    bool is_first_stage = (getenv("INIT_SECOND_STAGE") == nullptr);
964
965    if (is_first_stage) {
966        boot_clock::time_point start_time = boot_clock::now();
967
968        // Clear the umask.
969        umask(0);//清除屏蔽字(file mode creation mask),保证新建的目录的访问权限不受屏蔽字影响
970
971        // Get the basic filesystem setup we need put together in the initramdisk
972        // on / and then we'll let the rc file figure out the rest.
973        mount("tmpfs", "/dev", "tmpfs", MS_NOSUID, "mode=0755");
974        mkdir("/dev/pts", 0755);
975        mkdir("/dev/socket", 0755);
976        mount("devpts", "/dev/pts", "devpts", 0, NULL);
977        #define MAKE_STR(x) __STRING(x)
978        mount("proc", "/proc", "proc", 0, "hidepid=2,gid=" MAKE_STR(AID_READPROC));
979        // Don't expose the raw commandline to unprivileged processes.
980        chmod("/proc/cmdline", 0440);
981        gid_t groups[] = { AID_READPROC };
982        setgroups(arraysize(groups), groups);
983        mount("sysfs", "/sys", "sysfs", 0, NULL);
984        mount("selinuxfs", "/sys/fs/selinux", "selinuxfs", 0, NULL);
985        mknod("/dev/kmsg", S_IFCHR | 0600, makedev(1, 11));
986        mknod("/dev/random", S_IFCHR | 0666, makedev(1, 8));
987        mknod("/dev/urandom", S_IFCHR | 0666, makedev(1, 9));
988
989        // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually
990        // talk to the outside world...
991        InitKernelLogging(argv);
992
993        LOG(INFO) << "init first stage started!";
994
995        if (!DoFirstStageMount()) {
996            LOG(ERROR) << "Failed to mount required partitions early ...";
997            panic();
998        }
999
1000        SetInitAvbVersionInRecovery();
1001
1002        // Set up SELinux, loading the SELinux policy.
1003        selinux_initialize(true);
1004
1005        // We're in the kernel domain, so re-exec init to transition to the init domain now
1006        // that the SELinux policy has been loaded.
1007        if (restorecon("/init") == -1) {
1008            PLOG(ERROR) << "restorecon failed";
1009            security_failure();
1010        }
1011
1012        setenv("INIT_SECOND_STAGE", "true", 1);
1013
1014        static constexpr uint32_t kNanosecondsPerMillisecond = 1e6;
1015        uint64_t start_ms = start_time.time_since_epoch().count() / kNanosecondsPerMillisecond;
1016        setenv("INIT_STARTED_AT", StringPrintf("%" PRIu64, start_ms).c_str(), 1);
1017
1018        char* path = argv[0];
1019        char* args[] = { path, nullptr };
1020        execv(path, args);
1021
1022        // execv() only returns if an error happened, in which case we
1023        // panic and never fall through this conditional.
1024        PLOG(ERROR) << "execv(\"" << path << "\") failed";
1025        security_failure();
1026    }
1027
1028    // At this point we're in the second stage of init.
1029    InitKernelLogging(argv);
1030    LOG(INFO) << "init second stage started!";
1031
1032    // Set up a session keyring that all processes will have access to. It
1033    // will hold things like FBE encryption keys. No process should override
1034    // its session keyring.
1035    keyctl(KEYCTL_GET_KEYRING_ID, KEY_SPEC_SESSION_KEYRING, 1);
1036
1037    // Indicate that booting is in progress to background fw loaders, etc.
1038    close(open("/dev/.booting", O_WRONLY | O_CREAT | O_CLOEXEC, 0000));
1039
1040    property_init();// 初始化属性系统,将/dev/__properties__映射到共享内存
1041
1042    // If arguments are passed both on the command line and in DT,
1043    // properties set in DT always have priority over the command-line ones.
1044    process_kernel_dt();
1045    process_kernel_cmdline();
1046
1047    // Propagate the kernel variables to internal variables
1048    // used by init as well as the current required properties.
1049    export_kernel_boot_props();
1050
1051    // Make the time that init started available for bootstat to log.
1052    property_set("ro.boottime.init", getenv("INIT_STARTED_AT"));
1053    property_set("ro.boottime.init.selinux", getenv("INIT_SELINUX_TOOK"));
1054
1055    // Set libavb version for Framework-only OTA match in Treble build.
1056    const char* avb_version = getenv("INIT_AVB_VERSION");
1057    if (avb_version) property_set("ro.boot.avb_version", avb_version);
1058
1059    // Clean up our environment.
1060    unsetenv("INIT_SECOND_STAGE");
1061    unsetenv("INIT_STARTED_AT");
1062    unsetenv("INIT_SELINUX_TOOK");
1063    unsetenv("INIT_AVB_VERSION");
1064
1065    // Now set up SELinux for second stage.
1066    selinux_initialize(false);
1067    selinux_restore_context();
1068
1069    epoll_fd = epoll_create1(EPOLL_CLOEXEC);
1070    if (epoll_fd == -1) {
1071        PLOG(ERROR) << "epoll_create1 failed";
1072        exit(1);
1073    }
1074
1075    signal_handler_init();//信号系统初始化
1076
1077    property_load_boot_defaults();// 加载系统默认属性值
1078    export_oem_lock_status();
1079    start_property_service();// 启动属性服务
1080    set_usb_controller();
1081    // 解析初始化脚本
1082    const BuiltinFunctionMap function_map;
1083    Action::set_function_map(&function_map);
1084
1085    Parser& parser = Parser::GetInstance();
1086    parser.AddSectionParser("service",std::make_unique<ServiceParser>());
1087    parser.AddSectionParser("on", std::make_unique<ActionParser>());
1088    parser.AddSectionParser("import", std::make_unique<ImportParser>());
1089    std::string bootscript = GetProperty("ro.boot.init_rc", "");
1090    if (bootscript.empty()) {
1091        parser.ParseConfig("/init.rc");
1092        parser.set_is_system_etc_init_loaded(
1093                parser.ParseConfig("/system/etc/init"));
1094        parser.set_is_vendor_etc_init_loaded(
1095                parser.ParseConfig("/vendor/etc/init"));
1096        parser.set_is_odm_etc_init_loaded(parser.ParseConfig("/odm/etc/init"));
1097    } else {
1098        parser.ParseConfig(bootscript);
1099        parser.set_is_system_etc_init_loaded(true);
1100        parser.set_is_vendor_etc_init_loaded(true);
1101        parser.set_is_odm_etc_init_loaded(true);
1102    }
1103
1104    // Turning this on and letting the INFO logging be discarded adds 0.2s to
1105    // Nexus 9 boot time, so it's disabled by default.
1106    if (false) parser.DumpState();
1107
1108    ActionManager& am = ActionManager::GetInstance();
1109
1110    am.QueueEventTrigger("early-init");
1111
1112    // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev...
1113    am.QueueBuiltinAction(wait_for_coldboot_done_action, "wait_for_coldboot_done");
1114    // ... so that we can start queuing up actions that require stuff from /dev.
1115    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
1116    am.QueueBuiltinAction(set_mmap_rnd_bits_action, "set_mmap_rnd_bits");
1117    am.QueueBuiltinAction(set_kptr_restrict_action, "set_kptr_restrict");
1118    am.QueueBuiltinAction(keychord_init_action, "keychord_init");
1119    am.QueueBuiltinAction(console_init_action, "console_init");
1120
1121    // Trigger all the boot actions to get us started.
1122    am.QueueEventTrigger("init");
1123
1124    // Repeat mix_hwrng_into_linux_rng in case /dev/hw_random or /dev/random
1125    // wasn't ready immediately after wait_for_coldboot_done
1126    am.QueueBuiltinAction(mix_hwrng_into_linux_rng_action, "mix_hwrng_into_linux_rng");
1127
1128    // Don't mount filesystems or start core system services in charger mode.
1129    std::string bootmode = GetProperty("ro.bootmode", "");
1130    if (bootmode == "charger") {
1131        am.QueueEventTrigger("charger");
1132    } else {
1133        am.QueueEventTrigger("late-init");
1134    }
1135
1136    // Run all property triggers based on current state of the properties.
1137    am.QueueBuiltinAction(queue_property_triggers_action, "queue_property_triggers");
1138
1139    while (true) {
1140        // By default, sleep until something happens.
1141        int epoll_timeout_ms = -1;
1142
1143        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
1144            am.ExecuteOneCommand();
1145        }
1146        if (!(waiting_for_prop || ServiceManager::GetInstance().IsWaitingForExec())) {
1147            restart_processes();
1148
1149            // If there's a process that needs restarting, wake up in time for that.
1150            if (process_needs_restart_at != 0) {
1151                epoll_timeout_ms = (process_needs_restart_at - time(nullptr)) * 1000;
1152                if (epoll_timeout_ms < 0) epoll_timeout_ms = 0;
1153            }
1154
1155            // If there's more work to do, wake up again immediately.
1156            if (am.HasMoreCommands()) epoll_timeout_ms = 0;
1157        }
1158
1159        epoll_event ev;
1160        int nr = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd, &ev, 1, epoll_timeout_ms));
1161        if (nr == -1) {
1162            PLOG(ERROR) << "epoll_wait failed";
1163        } else if (nr == 1) {
1164            ((void (*)()) ev.data.ptr)();
1165        }
1166    }
1167
1168    return 0;
1169}

初始化属性系统共享内存

property_init()

代码路径:/system/core/init/property_service.cpp

 (http://androidxref.com/8.0.0_r4/xref/system/core/init/property_service.cpp)

68void property_init() {
69    if (__system_property_area_init()) {
70        LOG(ERROR) << "Failed to initialize property area";
71        exit(1);
72    }
73}

判断属性系统共享内存区域是否成功创建。


__system_property_area_init

代码路径:/bionic/libc/bionic/system_properties.cpp
 (http://androidxref.com/8.0.0_r4/xref/bionic/libc/bionic/system_properties.cpp)

1117int __system_property_area_init() {
1118  free_and_unmap_contexts();
1119  mkdir(property_filename, S_IRWXU | S_IXGRP | S_IXOTH);
1120  if (!initialize_properties()) {
1121    return -1;
1122  }
1123  bool open_failed = false;
1124  bool fsetxattr_failed = false;
1125  list_foreach(contexts, [&fsetxattr_failed, &open_failed](context_node* l) {
1126    if (!l->open(true, &fsetxattr_failed)) {
1127      open_failed = true;
1128    }
1129  });
1130  if (open_failed || !map_system_property_area(true, &fsetxattr_failed)) {//分配内存
1131    free_and_unmap_contexts();
1132    return -1;
1133  }
1134  initialized = true;
1135  return fsetxattr_failed ? -2 : 0;
1136}

在1130调用函数map_system_property_area创建一个共享内存区域,将文件映射到该内存区域


 

map_system_property_area

代码路径:/bionic/libc/bionic/system_properties.cpp (http://androidxref.com/8.0.0_r4/xref/bionic/libc/bionic/system_properties.cpp)

864static bool map_system_property_area(bool access_rw, bool* fsetxattr_failed) {
865  char filename[PROP_FILENAME_MAX];
866  int len =
867      __libc_format_buffer(filename, sizeof(filename), "%s/properties_serial", property_filename);
868  if (len < 0 || len > PROP_FILENAME_MAX) {
869    __system_property_area__ = nullptr;
870    return false;
871  }
872
873  if (access_rw) {
874    __system_property_area__ =
875        map_prop_area_rw(filename, "u:object_r:properties_serial:s0", fsetxattr_failed);
876  } else {
877    __system_property_area__ = map_prop_area(filename);//真正分配内存的地方
878  }
879  return __system_property_area__;
880}
 

加载系统属性文件

代码路径:/system/core/init/init.cpp

 (http://androidxref.com/8.0.0_r4/xref/system/core/init/init.cpp)

1077    property_load_boot_defaults();

完成了属性系统的内存初始化后,加载系统默认的属性值到内存区域

代码路径:/system/core/init/property_service.cpp

 (http://androidxref.com/8.0.0_r4/xref/system/core/init/property_service.cpp)

595void property_load_boot_defaults() {
596    if (!load_properties_from_file("/system/etc/prop.default", NULL)) {
597        // Try recovery path
598        if (!load_properties_from_file("/prop.default", NULL)) {
599            // Try legacy path
600            load_properties_from_file("/default.prop", NULL);
601        }
602    }
603    load_properties_from_file("/odm/default.prop", NULL);
604    load_properties_from_file("/vendor/default.prop", NULL);
605
606    update_sys_usb_config();
607}

加载属性默认的文件


代码路径:/system/core/init/property_service.cpp

 (http://androidxref.com/8.0.0_r4/xref/system/core/init/property_service.cpp)

509// Filter is used to decide which properties to load: NULL loads all keys,
510// "ro.foo.*" is a prefix match, and "ro.foo.bar" is an exact match.
511static bool load_properties_from_file(const char* filename, const char* filter) {
512    Timer t;
513    std::string data;
514    if (!read_file(filename, &data)) {
515        PLOG(WARNING) << "Couldn't load properties from " << filename;
516        return false;
517    }
518    data.push_back('\n');
519    load_properties(&data[0], filter);
520    LOG(VERBOSE) << "(Loading properties from " << filename << " took " << t << ".)";
521    return true;
522}

解析默认属性文件


启动属性服务,监听写操作

启动属性系统服务,其实就是创建一个名为property_service的socket,用于监听来自进程写系统属性的请求,同时注册在该socket上注册一个EPOLL时间的回调处理函数handle_property_set_fd:
代码路径:/system/core/init/init.cpp

 (http://androidxref.com/8.0.0_r4/xref/system/core/init/init.cpp)

 
1079    start_property_service();
启动属性服务

代码路径:/system/core/init/property_service.cpp

 (http://androidxref.com/8.0.0_r4/xref/system/core/init/property_service.cpp)

666void start_property_service() {
667    property_set("ro.property_service.version", "2");
668
669    property_set_fd = create_socket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
670                                    0666, 0, 0, NULL);//创建socket
671    if (property_set_fd == -1) {
672        PLOG(ERROR) << "start_property_service socket creation failed";
673        exit(1);
674    }
675
676    listen(property_set_fd, 8);
677
678    register_epoll_handler(property_set_fd, handle_property_set_fd);//注册处理函数
679}
EPOLL一旦有收到来自进程的写属性请求,就调用handle_property_set_fd,该函数首先接受socket绑定请求,接着接收消息数据,最后调用property_set设置属性:


代码路径:/system/core/init/property_service.cpp
 (http://androidxref.com/8.0.0_r4/xref/system/core/init/property_service.cpp)

382static void handle_property_set_fd() {
383    static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
384
385    int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);// 接受bind请求
386    if (s == -1) {
387        return;
388    }
389
390    struct ucred cr;
391    socklen_t cr_size = sizeof(cr);
392    if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {//取出客户端进程的权限等
393        close(s);
394        PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
395        return;
396    }
397
398    SocketConnection socket(s, cr);
399    uint32_t timeout_ms = kDefaultSocketTimeout;
400
401    uint32_t cmd = 0;
402    if (!socket.RecvUint32(&cmd, &timeout_ms)) {
403        PLOG(ERROR) << "sys_prop: error while reading command from the socket";
404        socket.SendUint32(PROP_ERROR_READ_CMD);
405        return;
406    }
407
408    switch (cmd) {
409    case PROP_MSG_SETPROP: {
410        char prop_name[PROP_NAME_MAX];
411        char prop_value[PROP_VALUE_MAX];
412
413        if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
414            !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
415          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
416          return;
417        }
418
419        prop_name[PROP_NAME_MAX-1] = 0;
420        prop_value[PROP_VALUE_MAX-1] = 0;
421
422        handle_property_set(socket, prop_value, prop_value, true);
423        break;
424      }
425
426    case PROP_MSG_SETPROP2: {
427        std::string name;
428        std::string value;
429        if (!socket.RecvString(&name, &timeout_ms) ||
430            !socket.RecvString(&value, &timeout_ms)) {
431          PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
432          socket.SendUint32(PROP_ERROR_READ_DATA);
433          return;
434        }
435
436        handle_property_set(socket, name, value, false);
437        break;
438      }
439
440    default:
441        LOG(ERROR) << "sys_prop: invalid command " << cmd;
442        socket.SendUint32(PROP_ERROR_INVALID_CMD);
443        break;
444    }
445}


334static void handle_property_set(SocketConnection& socket,
335                                const std::string& name,
336                                const std::string& value,
337                                bool legacy_protocol) {
338  const char* cmd_name = legacy_protocol ? "PROP_MSG_SETPROP" : "PROP_MSG_SETPROP2";
339  if (!is_legal_property_name(name)) {
340    LOG(ERROR) << "sys_prop(" << cmd_name << "): illegal property name \"" << name << "\"";
341    socket.SendUint32(PROP_ERROR_INVALID_NAME);
342    return;
343  }
344
345  struct ucred cr = socket.cred();
346  char* source_ctx = nullptr;
347  getpeercon(socket.socket(), &source_ctx);
348
349  if (android::base::StartsWith(name, "ctl.")) {
350    if (check_control_mac_perms(value.c_str(), source_ctx, &cr)) {
351      handle_control_message(name.c_str() + 4, value.c_str());
352      if (!legacy_protocol) {
353        socket.SendUint32(PROP_SUCCESS);
354      }
355    } else {
356      LOG(ERROR) << "sys_prop(" << cmd_name << "): Unable to " << (name.c_str() + 4)
357                 << " service ctl [" << value << "]"
358                 << " uid:" << cr.uid
359                 << " gid:" << cr.gid
360                 << " pid:" << cr.pid;
361      if (!legacy_protocol) {
362        socket.SendUint32(PROP_ERROR_HANDLE_CONTROL_MESSAGE);
363      }
364    }
365  } else {
366    if (check_mac_perms(name, source_ctx, &cr)) {
367      uint32_t result = property_set(name, value);
368      if (!legacy_protocol) {
369        socket.SendUint32(result);
370      }
371    } else {
372      LOG(ERROR) << "sys_prop(" << cmd_name << "): permission denied uid:" << cr.uid << " name:" << name;
373      if (!legacy_protocol) {
374        socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
375      }
376    }
377  }
378
379  freecon(source_ctx);
380}


访问系统属性值

Android提供了两种访问系统属性的方法,一种是通过JAVA Framework层的代码SystemProperties.java中提供的接口,由于该类接口并没有放入到SDK中,因此APP开发并不能使用此接口;一个是通过C++来访问,在代码中包含/system/core/include/cutils/properties.h头文件即可使用property_get/property_set来获取或者设置系统属性值。

Java: /frameworks/base/core/java/android/os/SystemProperties.java

C++: /system/core/libcutils/include/cutils/properties.h

实质上,两种方法最后都是通过bionic的libc库中的API来访问系统属性


代码路径:/system/core/libcutils/properties.cpp
 (http://androidxref.com/8.0.0_r4/xref/system/core/libcutils/properties.cpp)

调用libcutils中的property_get

114int property_get(const char *key, char *value, const char *default_value) {
115    int len = __system_property_get(key, value);
116    if (len > 0) {
117        return len;
118    }
119    if (default_value) {
120        len = strnlen(default_value, PROPERTY_VALUE_MAX - 1);
121        memcpy(value, default_value, len);
122        value[len] = '\0';
123    }
124    return len;
125}


代码路径:/bionic/libc/bionic/system_properties.cpp
 (http://androidxref.com/8.0.0_r4/xref/bionic/libc/bionic/system_properties.cpp)

在115行调用bionic中的__system_property_get:

1221int __system_property_get(const char* name, char* value) {
1222  const prop_info* pi = __system_property_find(name);
1223
1224  if (pi != 0) {
1225    return __system_property_read(pi, nullptr, value);
1226  } else {
1227    value[0] = 0;
1228    return 0;
1229  }
1230}


写系统属性

代码路径:/system/core/libcutils/properties.cpp

 (http://androidxref.com/8.0.0_r4/xref/system/core/libcutils/properties.cpp)

写系统属性与读属性不一样的地方在于需要通过一个socket来发送写请求。首先是通过libcutils库中的property_set来设置属性

110int property_set(const char *key, const char *value) {
111    return __system_property_set(key, value);
112}

在111行调用bionic中的__system_property_set


1257int __system_property_set(const char* key, const char* value) {
1258  if (key == nullptr) return -1;
1259  if (value == nullptr) value = "";
1260  if (strlen(value) >= PROP_VALUE_MAX) return -1;
1261
1262  if (g_propservice_protocol_version == 0) {
1263    detect_protocol_version();
1264  }
1265
1266  if (g_propservice_protocol_version == kProtocolVersion1) {
1267    // Old protocol does not support long names
1268    if (strlen(key) >= PROP_NAME_MAX) return -1;
1269
1270    prop_msg msg;
1271    memset(&msg, 0, sizeof msg);
1272    msg.cmd = PROP_MSG_SETPROP;
1273    strlcpy(msg.name, key, sizeof msg.name);
1274    strlcpy(msg.value, value, sizeof msg.value);
1275
1276    return send_prop_msg(&msg);
1277  } else {
          ...........................................
1329  }
1330}

在1276行调用send_prop_msg(&msg)向系统属性服务的socket/dev/socket/property_service发送写属性请求      


     获取一个本地socket文件描述符,并与系统属性服务的socket进行连接;
      连接成功后,向系统属性服务socket发送消息;
      等待系统属性服务返回写属性结果;

608static int send_prop_msg(const prop_msg* msg) {
609  PropertyServiceConnection connection;
610  if (!connection.IsValid()) {
611    return connection.GetLastError();
612  }
613
614  int result = -1;
615  int s = connection.socket();//获取一个本地socket文件描述符,并与系统属性服务的socket进行连接
616
617  const int num_bytes = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg), 0));// 发送消息到socket
618  if (num_bytes == sizeof(prop_msg)) {//等待系统属性服务返回写属性结果
619    // We successfully wrote to the property server but now we
620    // wait for the property server to finish its work.  It
621    // acknowledges its completion by closing the socket so we
622    // poll here (on nothing), waiting for the socket to close.
623    // If you 'adb shell setprop foo bar' you'll see the POLLHUP
624    // once the socket closes.  Out of paranoia we cap our poll
625    // at 250 ms.
626    pollfd pollfds[1];
627    pollfds[0].fd = s;
628    pollfds[0].events = 0;
629    const int poll_result = TEMP_FAILURE_RETRY(poll(pollfds, 1, 250 /* ms */));
630    if (poll_result == 1 && (pollfds[0].revents & POLLHUP) != 0) {
631      result = 0;
632    } else {
633      // Ignore the timeout and treat it like a success anyway.
634      // The init process is single-threaded and its property
635      // service is sometimes slow to respond (perhaps it's off
636      // starting a child process or something) and thus this
637      // times out and the caller thinks it failed, even though
638      // it's still getting around to it.  So we fake it here,
639      // mostly for ctl.* properties, but we do try and wait 250
640      // ms so callers who do read-after-write can reliably see
641      // what they've written.  Most of the time.
642      // TODO: fix the system properties design.
643      __libc_format_log(ANDROID_LOG_WARN, "libc",
644                        "Property service has timed out while trying to set \"%s\" to \"%s\"",
645                        msg->name, msg->value);
646      result = 0;
647    }
648  }
649
650  return result;
651}


系统属性服务监听到有消息时,调用回调函数handle_property_set_fd进行属性的修改

调用property_set修改系统属性:
从属性数据结构prop_area中查找给定的属性,返回prop_info;
如果当前存在该属性值,则直接更新,否则需要新建该属性prop_info;
对于persist的属性值,需要保存到文件/data/property中;

166uint32_t property_set(const std::string& name, const std::string& value) {
167    size_t valuelen = value.size();
168
169    if (!is_legal_property_name(name)) {
170        LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: bad name";
171        return PROP_ERROR_INVALID_NAME;
172    }
173
174    if (valuelen >= PROP_VALUE_MAX) {
175        LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
176                   << "value too long";
177        return PROP_ERROR_INVALID_VALUE;
178    }
179
180    if (name == "selinux.restorecon_recursive" && valuelen > 0) {
181        if (restorecon(value.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
182            LOG(ERROR) << "Failed to restorecon_recursive " << value;
183        }
184    }
185
186    prop_info* pi = (prop_info*) __system_property_find(name.c_str());//从属性数据结构prop_area中查找给定的属性,返回prop_info
187    if (pi != nullptr) {
188        // ro.* properties are actually "write-once".
189        if (android::base::StartsWith(name, "ro.")) {
190            LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
191                       << "property already set";
192            return PROP_ERROR_READ_ONLY_PROPERTY;
193        }
194
195        __system_property_update(pi, value.c_str(), valuelen);//如果当前存在该属性值,则直接更新,否则需要新建该属性prop_info
196    } else {
197        int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
198        if (rc < 0) {
199            LOG(ERROR) << "property_set(\"" << name << "\", \"" << value << "\") failed: "
200                       << "__system_property_add failed";
201            return PROP_ERROR_SET_FAILED;
202        }
203    }
204
205    // Don't write properties to disk until after we have read all default
206    // properties to prevent them from being overwritten by default values.
207    if (persistent_properties_loaded && android::base::StartsWith(name, "persist.")) {
208        write_persistent_property(name.c_str(), value.c_str());
209    }
210    property_changed(name, value);
211    return PROP_SUCCESS;
212}


如果系统属性已经加载完,则将修改后的persist系统属性保存到文件/data/property

118static void write_persistent_property(const char *name, const char *value)
119{
120    char tempPath[PATH_MAX];
121    char path[PATH_MAX];
122    int fd;
123
124    snprintf(tempPath, sizeof(tempPath), "%s/.temp.XXXXXX", PERSISTENT_PROPERTY_DIR);
125    fd = mkstemp(tempPath);
126    if (fd < 0) {
127        PLOG(ERROR) << "Unable to write persistent property to temp file " << tempPath;
128        return;
129    }
130    write(fd, value, strlen(value));
131    fsync(fd);
132    close(fd);
133
134    snprintf(path, sizeof(path), "%s/%s", PERSISTENT_PROPERTY_DIR, name);
135    if (rename(tempPath, path)) {
136        PLOG(ERROR) << "Unable to rename persistent property file " << tempPath << " to " << path;
137        unlink(tempPath);
138    }
139}

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值