• Android 12 init(3) 属性服务


    文章托管在gitee上 Android Notes , 同步csdn
    本文基于Android12 分析

    在 init 的启动第二阶段,启动属性服务线程,提供相关属性服务,给其他进程提供设置属性的支持,并通知init去处理属性事件。

    SecondStageMain

    /// system/core/init/init.cpp
    int SecondStageMain(int argc, char** argv) {
      ...
      PropertyInit(); // 属性环境相关初始化,及固有属性加载
      ...
      StartPropertyService(&property_fd); // 启动属性服务
      ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    PropertyInit

    /// @system/core/init/property_service.cpp
    void PropertyInit() {
        selinux_callback cb;
        cb.func_audit = PropertyAuditCallback;
        selinux_set_callback(SELINUX_CB_AUDIT, cb);
    
        mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH); // 创建/dev/__properties__目录,权限drwx--x--x
        CreateSerializedPropertyInfo(); // 创建property se contexts
        if (__system_property_area_init()) { // 将 /dev/__properties__/properties_serial 映射到内存, 创建 ContextNodes,映射节点
            LOG(FATAL) << "Failed to initialize property area";
        }
        if (!property_info_area.LoadDefaultPath()) { // 加载/dev/__properties__/property_info 映射进内存
            LOG(FATAL) << "Failed to load serialized property info file";
        }
    
        // If arguments are passed both on the command line and in DT,
        // properties set in DT always have priority over the command-line ones.
        ProcessKernelDt(); // 解析 /proc/device-tree/firmware/android/
        ProcessKernelCmdline(); // 解析 /proc/cmdline , 将其中键值对满足key为androidboot.* 的,将key替换为ro.boot.*,然后添加到属性
        ProcessBootconfig(); // 解析 /proc/bootconfig ,同上
    
        // Propagate the kernel variables to internal variables
        // used by init as well as the current required properties.
        ExportKernelBootProps(); // 给一些kernel属性初始赋值,如果没有设置的话
    
        // 加载默认的属性文件的属性
        // 如 /system/build.prop /vendor/default.prop /vendor/build.prop
        // 还会解析其他分区 如 odm、product、system_ext
        PropertyLoadBootDefaults();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    CreateSerializedPropertyInfo

    从相关property_contexts文件读取到context信息,并将内容序列化,然后写入 /dev/properties/property_info

    void CreateSerializedPropertyInfo() {
        auto property_infos = std::vector<PropertyInfoEntry>();
        // 从 selinux 的相关 property context 解析属性上下文信息,并存入 property_infos
        if (access("/system/etc/selinux/plat_property_contexts", R_OK) != -1) {
            if (!LoadPropertyInfoFromFile("/system/etc/selinux/plat_property_contexts",
                                          &property_infos)) {
                return;
            }
            // Don't check for failure here, since we don't always have all of these partitions.
            // E.g. In case of recovery, the vendor partition will not have mounted and we
            // still need the system / platform properties to function.
            if (access("/system_ext/etc/selinux/system_ext_property_contexts", R_OK) != -1) {
                LoadPropertyInfoFromFile("/system_ext/etc/selinux/system_ext_property_contexts",
                                         &property_infos);
            }
            if (!LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_property_contexts",
                                          &property_infos)) {
                // Fallback to nonplat_* if vendor_* doesn't exist.
                LoadPropertyInfoFromFile("/vendor/etc/selinux/nonplat_property_contexts",
                                         &property_infos);
            }
            if (access("/product/etc/selinux/product_property_contexts", R_OK) != -1) {
                LoadPropertyInfoFromFile("/product/etc/selinux/product_property_contexts",
                                         &property_infos);
            }
            if (access("/odm/etc/selinux/odm_property_contexts", R_OK) != -1) {
                LoadPropertyInfoFromFile("/odm/etc/selinux/odm_property_contexts", &property_infos);
            }
        } else {
            if (!LoadPropertyInfoFromFile("/plat_property_contexts", &property_infos)) {
                return;
            }
            LoadPropertyInfoFromFile("/system_ext_property_contexts", &property_infos);
            if (!LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos)) {
                // Fallback to nonplat_* if vendor_* doesn't exist.
                LoadPropertyInfoFromFile("/nonplat_property_contexts", &property_infos);
            }
            LoadPropertyInfoFromFile("/product_property_contexts", &property_infos);
            LoadPropertyInfoFromFile("/odm_property_contexts", &property_infos);
        }
    
        auto serialized_contexts = std::string();
        auto error = std::string();
        // 构建属性信息字典树,并将其序列化
        if (!BuildTrie(property_infos, "u:object_r:default_prop:s0", "string", &serialized_contexts,
                       &error)) {
            LOG(ERROR) << "Unable to serialize property contexts: " << error;
            return;
        }
    
        constexpr static const char kPropertyInfosPath[] = "/dev/__properties__/property_info";
        if (!WriteStringToFile(serialized_contexts, kPropertyInfosPath, 0444, 0, 0, false)) {// 写入property_info
            PLOG(ERROR) << "Unable to write serialized property infos to file";
        }
        selinux_android_restorecon(kPropertyInfosPath, 0);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    PropertyInfoEntry 定义如下,它用来存储解析后的context信息

    /// @system/core/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
    struct PropertyInfoEntry {
      PropertyInfoEntry() {}
      template <typename T, typename U, typename V>
      PropertyInfoEntry(T&& name, U&& context, V&& type, bool exact_match)
          : name(std::forward<T>(name)),
            context(std::forward<U>(context)),
            type(std::forward<V>(type)),
            exact_match(exact_match) {}
      std::string name;
      std::string context;
      std::string type;
      bool exact_match;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    查看 /system/etc/selinux/plat_property_contexts 其中一行,对应关系如下

    // name                context                            exact_match   type
    sys.shutdown.requested u:object_r:exported_system_prop:s0 exact         string
    
    • 1
    • 2

    __system_property_area_init

    将 /dev/properties/properties_serial 映射到内存, 创建 ContextNodes 流程

    #define PROP_FILENAME "/dev/__properties__"
    /// @bionic/libc/bionic/system_property_api.cpp
    __BIONIC_WEAK_FOR_NATIVE_BRIDGE
    int __system_property_area_init() {
      bool fsetxattr_failed = false;
      return system_properties.AreaInit(PROP_FILENAME, &fsetxattr_failed) && !fsetxattr_failed ? 0 : -1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    SystemProperties::AreaInit

    创建 ContextsSerialized 并初始化

    /// @bionic/libc/system_properties/system_properties.cpp
    bool SystemProperties::AreaInit(const char* filename, bool* fsetxattr_failed) {
      if (strlen(filename) >= PROP_FILENAME_MAX) {
        return false;
      }
      strcpy(property_filename_, filename); // filename 是 /dev/__properties__
    
      contexts_ = new (contexts_data_) ContextsSerialized();
      // 初始化 ContextsSerialized
      if (!contexts_->Initialize(true, property_filename_, fsetxattr_failed)) {
        return false;
      }
      initialized_ = true;
      return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    ContextsSerialized::Initialize

    第一个参数 writable 为 true, filename 为 /dev/properties

    /// @bionic/libc/system_properties/contexts_serialized.cpp
    bool ContextsSerialized::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) {
      filename_ = filename;  // 此处传入的是 /dev/__properties__
      if (!InitializeProperties()) { // 初始化属性
        return false;
      }
    
      if (writable) {
        mkdir(filename_, S_IRWXU | S_IXGRP | S_IXOTH);
        bool open_failed = false;
        if (fsetxattr_failed) {
          *fsetxattr_failed = false;
        }
        // 遍历 ContextNode 数组,将各个节点映射到内存
        for (size_t i = 0; i < num_context_nodes_; ++i) {
          if (!context_nodes_[i].Open(true, fsetxattr_failed)) { // 打开各个节点,并映射到内存,注意此处的true 表示access_rw
            open_failed = true;
          }
        }
        if (open_failed || !MapSerialPropertyArea(true, fsetxattr_failed)) { // /dev/__properties__/properties_serial 映射到内存
          FreeAndUnmap();
          return false;
        }
      } else {
        if (!MapSerialPropertyArea(false, nullptr)) {
          FreeAndUnmap();
          return false;
        }
      }
      return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    InitializeProperties

    /// @bionic/libc/system_properties/contexts_serialized.cpp
    bool ContextsSerialized::InitializeProperties() {
      if (!property_info_area_file_.LoadDefaultPath()) { // 加载 property_info
        return false;
      }
    
      if (!InitializeContextNodes()) { // 创建 context 节点集合
        FreeAndUnmap();
        return false;
      }
    
      return true;
    }
    
    /// 加载 /dev/__properties__/property_info
    bool PropertyInfoAreaFile::LoadDefaultPath() {
      return LoadPath("/dev/__properties__/property_info");
    }
    
    bool PropertyInfoAreaFile::LoadPath(const char* filename) {
      int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
    
      struct stat fd_stat;
      if (fstat(fd, &fd_stat) < 0) { // 获取fstat
        close(fd);
        return false;
      }
    
      if ((fd_stat.st_uid != 0) || (fd_stat.st_gid != 0) ||
          ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0) ||
          (fd_stat.st_size < static_cast<off_t>(sizeof(PropertyInfoArea)))) {
        close(fd);
        return false;
      }
    
      auto mmap_size = fd_stat.st_size;
      // 映射到内存
      void* map_result = mmap(nullptr, mmap_size, PROT_READ, MAP_SHARED, fd, 0);
      if (map_result == MAP_FAILED) {
        close(fd);
        return false;
      }
      // 转为具体类型
      auto property_info_area = reinterpret_cast<PropertyInfoArea*>(map_result);
      if (property_info_area->minimum_supported_version() > 1 ||
          property_info_area->size() != mmap_size) {
        munmap(map_result, mmap_size);
        close(fd);
        return false;
      }
    
      close(fd);
      mmap_base_ = map_result; // 记录地址和大小
      mmap_size_ = mmap_size;
      return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    InitializeContextNodes

    根据context信息创建对应的 ContextNode

    /// @bionic/libc/system_properties/include/system_properties/contexts_serialized.h
    android::properties::PropertyInfoAreaFile property_info_area_file_;// property info 映射文件
    ContextNode* context_nodes_ = nullptr;
    size_t num_context_nodes_ = 0;
    size_t context_nodes_mmap_size_ = 0;
    
    /// @bionic/libc/system_properties/contexts_serialized.cpp
    bool ContextsSerialized::InitializeContextNodes() {
      auto num_context_nodes = property_info_area_file_->num_contexts();
      auto context_nodes_mmap_size = sizeof(ContextNode) * num_context_nodes;
      // We want to avoid malloc in system properties, so we take an anonymous map instead (b/31659220).
      void* const map_result = mmap(nullptr, context_nodes_mmap_size, PROT_READ | PROT_WRITE,
                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); // 映射一个所有节点总大小空间
      if (map_result == MAP_FAILED) {
        return false;
      }
    
      prctl(PR_SET_VMA, PR_SET_VMA_ANON_NAME, map_result, context_nodes_mmap_size,
            "System property context nodes");
    
      context_nodes_ = reinterpret_cast<ContextNode*>(map_result);
      num_context_nodes_ = num_context_nodes;
      context_nodes_mmap_size_ = context_nodes_mmap_size;
      // 根据每个context创建对应的 ContextNode,并存入 context_nodes_,filename_ 是Initialize函数传入的 /dev/__properties__
      for (size_t i = 0; i < num_context_nodes; ++i) {
        new (&context_nodes_[i]) ContextNode(property_info_area_file_->context(i), filename_);
      }
    
      return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    创建每个节点后,接下来是调用它的Open函数

    ContextNode::Open

    从上面可以知道,init中 access_rw 传入的是 true

    /// @bionic/libc/system_properties/context_node.cpp
    bool ContextNode::Open(bool access_rw, bool* fsetxattr_failed) {
      lock_.lock();
      if (pa_) {
        lock_.unlock();
        return true;
      }
    
      char filename[PROP_FILENAME_MAX];
      // 此处构建的是 filename_/context_ , 比如 /dev/__properties__/u:object_r:vold_prop:s0
      int len = async_safe_format_buffer(filename, sizeof(filename), "%s/%s", filename_, context_);
      if (len < 0 || len >= PROP_FILENAME_MAX) {
        lock_.unlock();
        return false;
      }
    
      if (access_rw) { // 上面传入的是access_rw=true,调用map_prop_area_rw
        pa_ = prop_area::map_prop_area_rw(filename, context_, fsetxattr_failed); // 映射并记录地址,设置context
      } else {
        pa_ = prop_area::map_prop_area(filename);
      }
      lock_.unlock();
      return pa_;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    map_prop_area_rw 函数打开相关文件,然后将其映射到内存,返回内存地址指针。

    /// @bionic/libc/system_properties/prop_area.cpp
    prop_area* prop_area::map_prop_area_rw(const char* filename, const char* context,
                                           bool* fsetxattr_failed) {
      /* dev is a tmpfs that we can use to carve a shared workspace
       * out of, so let's do that...
       */  // 注意此处rwx权限是 444 只读, 因此只有 init 才有权限去写
      const int fd = open(filename, O_RDWR | O_CREAT | O_NOFOLLOW | O_CLOEXEC | O_EXCL, 0444);
    
      if (fd < 0) {
        if (errno == EACCES) {
          /* for consistency with the case where the process has already
           * mapped the page in and segfaults when trying to write to it
           */
          abort();
        }
        return nullptr;
      }
    
      if (context) { // 设置文件的context,比如 u:object_r:vold_prop:s0
        if (fsetxattr(fd, XATTR_NAME_SELINUX, context, strlen(context) + 1, 0) != 0) {
          async_safe_format_log(ANDROID_LOG_ERROR, "libc",
                                "fsetxattr failed to set context (%s) for \"%s\"", context, filename);
          /*
           * fsetxattr() will fail during system properties tests due to selinux policy.
           * We do not want to create a custom policy for the tester, so we will continue in
           * this function but set a flag that an error has occurred.
           * Init, which is the only daemon that should ever call this function will abort
           * when this error occurs.
           * Otherwise, the tester will ignore it and continue, albeit without any selinux
           * property separation.
           */
          if (fsetxattr_failed) {
            *fsetxattr_failed = true;
          }
        }
      }
    
      if (ftruncate(fd, PA_SIZE) < 0) {
        close(fd);
        return nullptr;
      }
    
      pa_size_ = PA_SIZE;
      pa_data_size_ = pa_size_ - sizeof(prop_area);
      // 映射到内存,具有读写权限
      void* const memory_area = mmap(nullptr, pa_size_, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
      if (memory_area == MAP_FAILED) {
        close(fd);
        return nullptr;
      }
    
      prop_area* pa = new (memory_area) prop_area(PROP_AREA_MAGIC, PROP_AREA_VERSION);
    
      close(fd);
      return pa;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56

    MapSerialPropertyArea

    最后将 /dev/__properties__/properties_serial 映射到内存,作为存储 context为 u:object_r:properties_serial:s0 的属性的文件

    /// @bionic/libc/system_properties/contexts_serialized.cpp
    bool ContextsSerialized::MapSerialPropertyArea(bool access_rw, bool* fsetxattr_failed) {
      char filename[PROP_FILENAME_MAX];
      int len = async_safe_format_buffer(filename, sizeof(filename), "%s/properties_serial", filename_);
      if (len < 0 || len >= PROP_FILENAME_MAX) {
        serial_prop_area_ = nullptr;
        return false;
      }
    
      if (access_rw) {
        serial_prop_area_ =  // 映射到内存,并设置context为 u:object_r:properties_serial:s0
            prop_area::map_prop_area_rw(filename, "u:object_r:properties_serial:s0", fsetxattr_failed);
      } else {
        serial_prop_area_ = prop_area::map_prop_area(filename);
      }
      return serial_prop_area_;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    总结一下上面__system_property_area_init()流程:

    • 创建/dev/__properties__目录,权限drwx–x–x
    • 解析property context文件并将信息存储到 /dev/__properties__/property_info
    • 映射property_info,读取property context并根据每个context创建对应的 ContextNode
    • ContextNode::Open 创建节点文件并以读写映射到内存
    • 将/dev/__properties__/properties_serial 映射到内存

    到此 __system_property_area_init() 完成,创建了所有context对应的节点并映射到内存以及映射properties_serial,可以查看/dev/__properties__

    # ls /dev/__properties__/ -lZ
    total 1136
    -r--r--r-- 1 root root u:object_r:properties_serial:s0                                131072 2022-11-30 14:24 properties_serial
    -r--r--r-- 1 root root u:object_r:property_info:s0                                     64956 2022-11-30 14:24 property_info
    -r--r--r-- 1 root root u:object_r:aac_drc_prop:s0                                     131072 2022-11-30 14:24 u:object_r:aac_drc_prop:s0
    -r--r--r-- 1 root root u:object_r:aaudio_config_prop:s0                               131072 2022-11-30 14:24 u:object_r:aaudio_config_prop:s0
    -r--r--r-- 1 root root u:object_r:ab_update_gki_prop:s0                               131072 2022-11-30 14:24 u:object_r:ab_update_gki_prop:s0
    -r--r--r-- 1 root root u:object_r:adbd_config_prop:s0                                 131072 2022-11-30 14:24 u:object_r:adbd_config_prop:s0
    -r--r--r-- 1 root root u:object_r:adbd_prop:s0                                        131072 2022-11-30 14:24 u:object_r:adbd_prop:s0
    -r--r--r-- 1 root root u:object_r:apexd_config_prop:s0                                131072 2022-11-30 14:24 u:object_r:apexd_config_prop:s0
    -r--r--r-- 1 root root u:object_r:apexd_prop:s0                                       131072 2022-11-30 14:24 u:object_r:apexd_prop:s0
    ...
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    property_info_area.LoadDefaultPath

    加载 /dev/__properties__/property_info 并映射到内存,逻辑同之前 property_info_area_file_ 加载

    bool PropertyInfoAreaFile::LoadDefaultPath() {
      return LoadPath("/dev/__properties__/property_info");
    }
    
    • 1
    • 2
    • 3

    ProcessKernelCmdline / ProcessBootconfig

    /// @system/core/init/property_service.cpp
    constexpr auto ANDROIDBOOT_PREFIX = "androidboot."sv;
    
    static void ProcessKernelCmdline() {
        // 加载 /proc/cmdline
        ImportKernelCmdline([&](const std::string& key, const std::string& value) {
            if (StartsWith(key, ANDROIDBOOT_PREFIX)) { // key 起始是 androidboot
                // 将key起始位置替换为ro.boot, 然后设置新属性
                InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
            }
        });
    }
    
    static void ProcessBootconfig() {
        // 加载 /proc/bootconfig
        ImportBootconfig([&](const std::string& key, const std::string& value) {
            if (StartsWith(key, ANDROIDBOOT_PREFIX)) { // key 起始是 androidboot
                // 将key起始位置替换为ro.boot, 然后设置新属性
                InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
            }
        });
    }
    
    // 读取/proc/cmdline , 匹配回调 fn
    void ImportKernelCmdline(const std::function<void(const std::string&, const std::string&)>& fn) {
        std::string cmdline;
        android::base::ReadFileToString("/proc/cmdline", &cmdline);
    
        for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
            std::vector<std::string> pieces = android::base::Split(entry, "=");
            if (pieces.size() == 2) {
                fn(pieces[0], pieces[1]);
            }
        }
    }
    
    // 读取/proc/bootconfig , 匹配回调 fn
    void ImportBootconfig(const std::function<void(const std::string&, const std::string&)>& fn) {
        std::string bootconfig;
        android::base::ReadFileToString("/proc/bootconfig", &bootconfig);
    
        for (const auto& entry : android::base::Split(bootconfig, "\n")) {
            std::vector<std::string> pieces = android::base::Split(entry, "=");
            if (pieces.size() == 2) {
                // get rid of the extra space between a list of values and remove the quotes.
                std::string value = android::base::StringReplace(pieces[1], "\", \"", ",", true);
                value.erase(std::remove(value.begin(), value.end(), '"'), value.end());
                fn(android::base::Trim(pieces[0]), android::base::Trim(value));
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    PropertyLoadBootDefaults

    加载开机默认属性

    /// @system/core/init/property_service.cpp
    void PropertyLoadBootDefaults() {
        // We read the properties and their values into a map, in order to always allow properties
        // loaded in the later property files to override the properties in loaded in the earlier
        // property files, regardless of if they are "ro." properties or not.
        std::map<std::string, std::string> properties;
    
        if (IsRecoveryMode()) {
            load_properties_from_file("/prop.default", nullptr, &properties);
        }
    
        // //etc/build.prop is the canonical location of the build-time properties since S.
        // Falling back to //defalt.prop and //build.prop only when legacy path has to
        // be supported, which is controlled by the support_legacy_path_until argument.
        const auto load_properties_from_partition = [&properties](const std::string& partition,
                                                                  int support_legacy_path_until) {  // 加载某个分区的lambda表达式
            auto path = "/" + partition + "/etc/build.prop";
            if (load_properties_from_file(path.c_str(), nullptr, &properties)) {
                return;
            }
            // To read ro..build.version.sdk, temporarily load the legacy paths into a
            // separate map. Then by comparing its value with legacy_version, we know that if the
            // partition is old enough so that we need to respect the legacy paths.
            std::map<std::string, std::string> temp;
            auto legacy_path1 = "/" + partition + "/default.prop";
            auto legacy_path2 = "/" + partition + "/build.prop";
            load_properties_from_file(legacy_path1.c_str(), nullptr, &temp);
            load_properties_from_file(legacy_path2.c_str(), nullptr, &temp);
            bool support_legacy_path = false;
            auto version_prop_name = "ro." + partition + ".build.version.sdk";
            auto it = temp.find(version_prop_name);
            if (it == temp.end()) {
                // This is embarassing. Without the prop, we can't determine how old the partition is.
                // Let's be conservative by assuming it is very very old.
                support_legacy_path = true;
            } else if (int value;
                       ParseInt(it->second.c_str(), &value) && value <= support_legacy_path_until) {
                support_legacy_path = true;
            }
            if (support_legacy_path) {
                // We don't update temp into properties directly as it might skip any (future) logic
                // for resolving duplicates implemented in load_properties_from_file.  Instead, read
                // the files again into the properties map.
                load_properties_from_file(legacy_path1.c_str(), nullptr, &properties);
                load_properties_from_file(legacy_path2.c_str(), nullptr, &properties);
            } else {
                LOG(FATAL) << legacy_path1 << " and " << legacy_path2 << " were not loaded "
                           << "because " << version_prop_name << "(" << it->second << ") is newer "
                           << "than " << support_legacy_path_until;
            }
        };
    
        // Order matters here. The more the partition is specific to a product, the higher its
        // precedence is.
        LoadPropertiesFromSecondStageRes(&properties);
        load_properties_from_file("/system/build.prop", nullptr, &properties); // 加载某个文件
        load_properties_from_partition("system_ext", /* support_legacy_path_until */ 30);  // 加载某个分区的
        // TODO(b/117892318): uncomment the following condition when vendor.imgs for aosp_* targets are
        // all updated.
        // if (SelinuxGetVendorAndroidVersion() <= __ANDROID_API_R__) {
        load_properties_from_file("/vendor/default.prop", nullptr, &properties);
        // }
        load_properties_from_file("/vendor/build.prop", nullptr, &properties);
        load_properties_from_file("/vendor_dlkm/etc/build.prop", nullptr, &properties);
        load_properties_from_file("/odm_dlkm/etc/build.prop", nullptr, &properties);
        load_properties_from_partition("odm", /* support_legacy_path_until */ 28);
        load_properties_from_partition("product", /* support_legacy_path_until */ 30);
    
        if (access(kDebugRamdiskProp, R_OK) == 0) {
            LOG(INFO) << "Loading " << kDebugRamdiskProp;
            load_properties_from_file(kDebugRamdiskProp, nullptr, &properties);
        }
    
        for (const auto& [name, value] : properties) { // 将加载的属性键值对执行设置操作,保持到映射区
            std::string error;
            if (PropertySet(name, value, &error) != PROP_SUCCESS) {
                LOG(ERROR) << "Could not set '" << name << "' to '" << value
                           << "' while loading .prop files" << error;
            }
        }
        // 启动属性初始化
        property_initialize_ro_product_props();
        property_initialize_build_id();
        property_derive_build_fingerprint();
        property_derive_legacy_build_fingerprint();
        property_initialize_ro_cpu_abilist();
    
        update_sys_usb_config();  // 更新usb配置属性
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    update_sys_usb_config

    // persist.sys.usb.config values can't be combined on build-time when property
    // files are split into each partition.
    // So we need to apply the same rule of build/make/tools/post_process_props.py
    // on runtime.
    static void update_sys_usb_config() {
        bool is_debuggable = android::base::GetBoolProperty("ro.debuggable", false);
        std::string config = android::base::GetProperty("persist.sys.usb.config", "");
        // b/150130503, add (config == "none") condition here to prevent appending
        // ",adb" if "none" is explicitly defined in default prop.
        if (config.empty() || config == "none") {
            InitPropertySet("persist.sys.usb.config", is_debuggable ? "adb" : "none");
        } else if (is_debuggable && config.find("adb") == std::string::npos &&
                   config.length() + 4 < PROP_VALUE_MAX) {
            config.append(",adb");
            InitPropertySet("persist.sys.usb.config", config);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    StartPropertyService

    启动属性服务

    /// @system/core/init/property_service.cpp
    void StartPropertyService(int* epoll_socket) {
        InitPropertySet("ro.property_service.version", "2");
    
        int sockets[2];
        // 创建 socket 对,用于init和属性服务间通信
        if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0) {
            PLOG(FATAL) << "Failed to socketpair() between property_service and init";
        }
        *epoll_socket = from_init_socket = sockets[0]; // 回传给init端
        init_socket = sockets[1]; // 持有此fd端
        StartSendingMessages(); // 设置 accept_messages = true , 表示可以处理请求消息
    
        // 创建接收属性请求的 socket
        if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                       false, 0666, 0, 0, {});
            result.ok()) {
            property_set_fd = *result; // 记录此fd
        } else {
            LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
        }
    
        listen(property_set_fd, 8); // 监听
    
        auto new_thread = std::thread{PropertyServiceThread}; // 创建新线程,调用PropertyServiceThread用于处理请求,
        property_service_thread.swap(new_thread);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    PropertyServiceThread

    /// @system/core/init/property_service.cpp
    static void PropertyServiceThread() {
        Epoll epoll;
        if (auto result = epoll.Open(); !result.ok()) { // 创建 epoll
            LOG(FATAL) << result.error();
        }
        // 将属性设置fd注册到epoll,监听其相关事件
        if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);
            !result.ok()) {
            LOG(FATAL) << result.error();
        }
        // 注册init_socket到epoll,监听来自init相关事件
        if (auto result = epoll.RegisterHandler(init_socket, HandleInitSocket); !result.ok()) {
            LOG(FATAL) << result.error();
        }
    
        while (true) { // 循环处理事件
            auto pending_functions = epoll.Wait(std::nullopt); // 等待事件发生
            if (!pending_functions.ok()) {
                LOG(ERROR) << pending_functions.error();
            } else {
                for (const auto& function : *pending_functions) {
                    (*function)();
                }
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    当收到设置属性请求时,会回调 handle_property_set_fd 函数

    handle_property_set_fd

    /// @system/core/init/property_service.cpp
    static void handle_property_set_fd() {
        static constexpr uint32_t kDefaultSocketTimeout = 2000; /* ms */
    
        int s = accept4(property_set_fd, nullptr, nullptr, SOCK_CLOEXEC);
        if (s == -1) {
            return;
        }
    
        ucred cr;
        socklen_t cr_size = sizeof(cr);
        if (getsockopt(s, SOL_SOCKET, SO_PEERCRED, &cr, &cr_size) < 0) {
            close(s);
            PLOG(ERROR) << "sys_prop: unable to get SO_PEERCRED";
            return;
        }
    
        SocketConnection socket(s, cr);
        uint32_t timeout_ms = kDefaultSocketTimeout;
    
        uint32_t cmd = 0;
        if (!socket.RecvUint32(&cmd, &timeout_ms)) {
            PLOG(ERROR) << "sys_prop: error while reading command from the socket";
            socket.SendUint32(PROP_ERROR_READ_CMD);
            return;
        }
    
        switch (cmd) {
        case PROP_MSG_SETPROP: {
            char prop_name[PROP_NAME_MAX];
            char prop_value[PROP_VALUE_MAX];
    
            if (!socket.RecvChars(prop_name, PROP_NAME_MAX, &timeout_ms) ||
                !socket.RecvChars(prop_value, PROP_VALUE_MAX, &timeout_ms)) {
              PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP): error while reading name/value from the socket";
              return;
            }
    
            prop_name[PROP_NAME_MAX-1] = 0;
            prop_value[PROP_VALUE_MAX-1] = 0;
    
            std::string source_context;
            if (!socket.GetSourceContext(&source_context)) {
                PLOG(ERROR) << "Unable to set property '" << prop_name << "': getpeercon() failed";
                return;
            }
    
            const auto& cr = socket.cred();
            std::string error;
            uint32_t result =
                    HandlePropertySet(prop_name, prop_value, source_context, cr, nullptr, &error);
            if (result != PROP_SUCCESS) {
                LOG(ERROR) << "Unable to set property '" << prop_name << "' from uid:" << cr.uid
                           << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
            }
    
            break;
          }
    
        case PROP_MSG_SETPROP2: {
            std::string name;
            std::string value;
            if (!socket.RecvString(&name, &timeout_ms) ||
                !socket.RecvString(&value, &timeout_ms)) {
              PLOG(ERROR) << "sys_prop(PROP_MSG_SETPROP2): error while reading name/value from the socket";
              socket.SendUint32(PROP_ERROR_READ_DATA);
              return;
            }
    
            std::string source_context;
            if (!socket.GetSourceContext(&source_context)) {
                PLOG(ERROR) << "Unable to set property '" << name << "': getpeercon() failed";
                socket.SendUint32(PROP_ERROR_PERMISSION_DENIED);
                return;
            }
    
            const auto& cr = socket.cred();
            std::string error; // 调用 HandlePropertySet 设置属性
            uint32_t result = HandlePropertySet(name, value, source_context, cr, &socket, &error);
            if (result != PROP_SUCCESS) {
                LOG(ERROR) << "Unable to set property '" << name << "' from uid:" << cr.uid
                           << " gid:" << cr.gid << " pid:" << cr.pid << ": " << error;
            }
            socket.SendUint32(result);
            break;
          }
    
        default:
            LOG(ERROR) << "sys_prop: invalid command " << cmd;
            socket.SendUint32(PROP_ERROR_INVALID_CMD);
            break;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    HandlePropertySet

    处理设置属性

    /// @system/core/init/property_service.cpp
    // This returns one of the enum of PROP_SUCCESS or PROP_ERROR*.
    uint32_t HandlePropertySet(const std::string& name, const std::string& value,
                               const std::string& source_context, const ucred& cr,
                               SocketConnection* socket, std::string* error) {
        // 权限检查                         
        if (auto ret = CheckPermissions(name, value, source_context, cr, error); ret != PROP_SUCCESS) {
            return ret;
        }
    
        if (StartsWith(name, "ctl.")) { // 处理 ctl 属性
            return SendControlMessage(name.c_str() + 4, value, cr.pid, socket, error);
        }
    
        // sys.powerctl is a special property that is used to make the device reboot.  We want to log
        // any process that sets this property to be able to accurately blame the cause of a shutdown.
        if (name == "sys.powerctl") { // 处理关机/重启请求
            std::string cmdline_path = StringPrintf("proc/%d/cmdline", cr.pid); // 读取请求进程信息
            std::string process_cmdline;
            std::string process_log_string;
            if (ReadFileToString(cmdline_path, &process_cmdline)) {
                // Since cmdline is null deliminated, .c_str() conveniently gives us just the process
                // path.
                process_log_string = StringPrintf(" (%s)", process_cmdline.c_str());
            }
            LOG(INFO) << "Received sys.powerctl='" << value << "' from pid: " << cr.pid
                      << process_log_string;
            if (!value.empty()) {
                DebugRebootLogging();
            }
            if (value == "reboot,userspace" && !is_userspace_reboot_supported().value_or(false)) {
                *error = "Userspace reboot is not supported by this device";
                return PROP_ERROR_INVALID_VALUE;
            }
        }
    
        // If a process other than init is writing a non-empty value, it means that process is
        // requesting that init performs a restorecon operation on the path specified by 'value'.
        // We use a thread to do this restorecon operation to prevent holding up init, as it may take
        // a long time to complete.
        if (name == kRestoreconProperty && cr.pid != 1 && !value.empty()) {
            static AsyncRestorecon async_restorecon;
            async_restorecon.TriggerRestorecon(value);
            return PROP_SUCCESS;
        }
    
        return PropertySet(name, value, error); // 真正设置更新
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48

    PropertySet

    /// @system/core/init/property_service.cpp
    static uint32_t PropertySet(const std::string& name, const std::string& value, std::string* error) {
        size_t valuelen = value.size();
    
        if (!IsLegalPropertyName(name)) { // 值合法性检查
            *error = "Illegal property name";
            return PROP_ERROR_INVALID_NAME;
        }
    
        if (auto result = IsLegalPropertyValue(name, value); !result.ok()) {  // 值合法性检查
            *error = result.error().message();
            return PROP_ERROR_INVALID_VALUE;
        }
    
        prop_info* pi = (prop_info*) __system_property_find(name.c_str());  // 查找属性信息是否存在
        if (pi != nullptr) {
            // ro.* properties are actually "write-once".
            if (StartsWith(name, "ro.")) {  // 只读属性不能设置
                *error = "Read-only property was already set";
                return PROP_ERROR_READ_ONLY_PROPERTY;
            }
    
            __system_property_update(pi, value.c_str(), valuelen); // 更新
        } else {// 添加属性
            int rc = __system_property_add(name.c_str(), name.size(), value.c_str(), valuelen);
            if (rc < 0) {
                *error = "__system_property_add failed";
                return PROP_ERROR_SET_FAILED;
            }
        }
    
        // Don't write properties to disk until after we have read all default
        // properties to prevent them from being overwritten by default values.
        if (persistent_properties_loaded && StartsWith(name, "persist.")) {
            WritePersistentProperty(name, value);  // 写入 persist 属性
        }
        // If init hasn't started its main loop, then it won't be handling property changed messages
        // anyway, so there's no need to try to send them.
        auto lock = std::lock_guard{accept_messages_lock};
        if (accept_messages) {
            PropertyChanged(name, value);  //通知属性变化
        }
        return PROP_SUCCESS;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    PropertyChanged

    属性变化处理逻辑

    /// @system/core/init/init.cpp
    void PropertyChanged(const std::string& name, const std::string& value) {
        // If the property is sys.powerctl, we bypass the event queue and immediately handle it.
        // This is to ensure that init will always and immediately shutdown/reboot, regardless of
        // if there are other pending events to process or if init is waiting on an exec service or
        // waiting on a property.
        // In non-thermal-shutdown case, 'shutdown' trigger will be fired to let device specific
        // commands to be executed.
        if (name == "sys.powerctl") { // 处理关机请求
            trigger_shutdown(value);
        }
    
        if (property_triggers_enabled) {// 已经使能属性触发器
            ActionManager::GetInstance().QueuePropertyChange(name, value); //添加到事件队列
            WakeMainInitThread(); // 唤醒init主线程处理
        }
    
        prop_waiter_state.CheckAndResetWait(name, value); // 检查是否有设置等待此属性值
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    ActionManager::QueuePropertyChange

    /// @system/core/init/action_manager.cpp
    void ActionManager::QueuePropertyChange(const std::string& name, const std::string& value) {
        auto lock = std::lock_guard{event_queue_lock_};
        event_queue_.emplace(std::make_pair(name, value)); // 插入一个属性变化的事件
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    WakeMainInitThread

    /// @system/core/init/init.cpp
    static void WakeMainInitThread() {
        uint64_t counter = 1; // 写入一个数据,唤醒对端
        TEMP_FAILURE_RETRY(write(wake_main_thread_fd, &counter, sizeof(counter)));
    }
    
    // Init epolls various FDs to wait for various inputs.  It previously waited on property changes
    // with a blocking socket that contained the information related to the change, however, it was easy
    // to fill that socket and deadlock the system.  Now we use locks to handle the property changes
    // directly in the property thread, however we still must wake the epoll to inform init that there
    // is a change to process, so we use this FD.  It is non-blocking, since we do not care how many
    // times WakeMainInitThread() is called, only that the epoll will wake.
    static int wake_main_thread_fd = -1;
    static void InstallInitNotifier(Epoll* epoll) { // 在启动属性服务之前,调用来设置醒监听
        wake_main_thread_fd = eventfd(0, EFD_CLOEXEC); // 初始化一个event fd
        if (wake_main_thread_fd == -1) {
            PLOG(FATAL) << "Failed to create eventfd for waking init";
        }
        auto clear_eventfd = [] { // epoll收到相关事件会回调此lambda
            uint64_t counter; // 仅仅只是读出来,消费掉事件。主要目的是唤醒epoll
            TEMP_FAILURE_RETRY(read(wake_main_thread_fd, &counter, sizeof(counter)));
        };
        // 注册到epoll 监听写事件
        if (auto result = epoll->RegisterHandler(wake_main_thread_fd, clear_eventfd); !result.ok()) {
            LOG(FATAL) << result.error();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    SecondStageMain 处理属性事件

    int SecondStageMain(int argc, char** argv) {
    ...
    // Restore prio before main loop
    setpriority(PRIO_PROCESS, 0, 0);
    while (true) {
        // By default, sleep until something happens.
        auto epoll_timeout = std::optional<std::chrono::milliseconds>{};
    
        auto shutdown_command = shutdown_state.CheckShutdown();
        if (shutdown_command) { // 处理关机请求
            LOG(INFO) << "Got shutdown_command '" << *shutdown_command
                      << "' Calling HandlePowerctlMessage()";
            HandlePowerctlMessage(*shutdown_command);
            shutdown_state.set_do_shutdown(false);
        }
        // 当没有要等待的属性或执行的服务 则从事件队列中取出一个执行
        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            am.ExecuteOneCommand();
        }
        if (!IsShuttingDown()) { // 不是正在关机, 如有需要重启的服务,需要据此重新计算超时时间
            auto next_process_action_time = HandleProcessActions();
    
            // If there's a process that needs restarting, wake up in time for that.
            if (next_process_action_time) {
                epoll_timeout = std::chrono::ceil<std::chrono::milliseconds>(
                        *next_process_action_time - boot_clock::now());
                if (*epoll_timeout < 0ms) epoll_timeout = 0ms;
            }
        }
    
        if (!(prop_waiter_state.MightBeWaiting() || Service::is_exec_service_running())) {
            // If there's more work to do, wake up again immediately.
            if (am.HasMoreCommands()) epoll_timeout = 0ms; // 还有事件需要处理,超时为0,即里面处理下个事件
        }
    
        auto pending_functions = epoll.Wait(epoll_timeout); // 等待到新消息到来或超时
        if (!pending_functions.ok()) {
            LOG(ERROR) << pending_functions.error();
        } else if (!pending_functions->empty()) { // 有待执行命令,比如唤醒要执行的回调 clear_eventfd
            // We always reap children before responding to the other pending functions. This is to
            // prevent a race where other daemons see that a service has exited and ask init to
            // start it again via ctl.start before init has reaped it.
            ReapAnyOutstandingChildren(); // 首先回收已退出的进程,回收僵尸进程
            for (const auto& function : *pending_functions) { // 执行相关回调
                (*function)();
            }
        }
        if (!IsShuttingDown()) { // 不是正在关机,
            HandleControlMessages(); // 处理 ctl 属性消息
            SetUsbController();
        }
    }
    
    return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    如上,当属性服务写数据时唤醒epoll,epoll从Wait函数返回,然后处理此事件,回调clear_eventfd来消耗掉此事件。由此主线程达到了唤醒的目的,然后下次循环,通过 am.ExecuteOneCommand 来取出属性事件对应的action来执行。

    ActionManager::ExecuteOneCommand

    /// @system/core/init/action_manager.cpp
    void ActionManager::ExecuteOneCommand() {
        {
            auto lock = std::lock_guard{event_queue_lock_};
            // Loop through the event queue until we have an action to execute
            while (current_executing_actions_.empty() && !event_queue_.empty()) { // 当前没有执行的action,但是有事件
                for (const auto& action : actions_) { // 找到此事件对应要处理的action
                    if (std::visit([&action](const auto& event) { return action->CheckEvent(event); },
                                   event_queue_.front())) {
                        current_executing_actions_.emplace(action.get()); // 一个事件可以对应多个 action
                    }
                }
                event_queue_.pop();
            }
        }
    
        if (current_executing_actions_.empty()) {
            return;
        }
        // 返回 queue 中第一个元素的引用,而不是删除
        auto action = current_executing_actions_.front();
    
        if (current_command_ == 0) { // 处理此action的第一条命令时打印
            std::string trigger_name = action->BuildTriggersString();
            LOG(INFO) << "processing action (" << trigger_name << ") from (" << action->filename()
                      << ":" << action->line() << ")";
        }
    
        action->ExecuteOneCommand(current_command_); // 回调每个action匹配的命令
    
        // If this was the last command in the current action, then remove
        // the action from the executing list.
        // If this action was oneshot, then also remove it from actions_.
        ++current_command_;  // 每执行一次数量加1
        if (current_command_ == action->NumCommands()) { // 如果此 action的命令全部执行完毕
            current_executing_actions_.pop(); // 从正执行列表删除
            current_command_ = 0;
            if (action->oneshot()) { // 如果是一次性的 还有从action列表移除。 通常Builtin Action是一次性的
                auto eraser = [&action](std::unique_ptr<Action>& a) { return a.get() == action; };
                actions_.erase(std::remove_if(actions_.begin(), actions_.end(), eraser),
                               actions_.end());
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    接下来的流程和 init(2) rc脚本解析和事件执行流程 类似,就不在赘述了。

    示例:设置属性 persist.traced.enable

    当设置属性 persist.traced.enable 为 1, 以下动作将会触发,会依次执行 mkdir命令和 start 命令。

    /// perfetto.rc
    on property:persist.traced.enable=1
        # Trace files need to be:
        # - Written by either uid:shell or uid:statsd.
        # - Read by shell and incidentd.
        mkdir /data/misc/perfetto-traces 0773 root shell
    
        # Traces in this directory are only accessed by dumpstate (read+unlink) and
        # by the bug reporting UI (ls+getattr).
        mkdir /data/misc/perfetto-traces/bugreport 0773 root shell
    
        # This directory allows shell to save configs file in a place where the
        # perfetto cmdline client can read then. /data/local/tmp/ isn't safe because
        # too many other domains can write into that. See b/170404111.
        mkdir /data/misc/perfetto-configs 0775 root shell
    
        start traced
        start traced_probes
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    获取属性流程

    接下来分析如何获取属性,以java层的SystemProperties的get获取方式来分析这个过程

    SystemProperties#get

    frameworks/base/core/java/android/os/SystemProperties.java
    /**
     * Get the String value for the given {@code key}.
     *
     * @param key the key to lookup
     * @return an empty string if the {@code key} isn't found
     * @hide
     */
    @NonNull
    @SystemApi
    public static String get(@NonNull String key) {
        if (TRACK_KEY_ACCESS) onKeyAccess(key);
        return native_get(key);
    }
    
    // The one-argument version of native_get used to be a regular native function.
    @UnsupportedAppUsage
    private static String native_get(String key) {
        return native_get(key, "");
    }
    
    @FastNative
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    private static native String native_get(String key, String def); // 最后调用  native 方法
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    native_get方法 对应的jni函数是SystemProperties_getSS

    frameworks/base/core/jni/android_os_SystemProperties.cpp
    const JNINativeMethod method_table[] = {
        { "native_get",
          "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
          (void*) SystemProperties_getSS },
          ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    SystemProperties_getSS

    /// @frameworks/base/core/jni/android_os_SystemProperties.cpp
    jstring SystemProperties_getSS(JNIEnv* env, jclass clazz, jstring keyJ, jstring defJ)
    {
        jstring ret = defJ;
        ReadProperty(env, keyJ, [&](const char* value) { // 读取属性,此处lambda是Functor回调
            if (value[0]) {
                ret = env->NewStringUTF(value);
            }
        });
        if (ret == nullptr && !env->ExceptionCheck()) {
          ret = env->NewStringUTF("");  // Legacy behavior
        }
        return ret;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    ReadProperty

    template<typename Functor>
    void ReadProperty(JNIEnv* env, jstring keyJ, Functor&& functor)
    {
        ScopedUtfChars key(env, keyJ);
        if (!key.c_str()) {
            return;
        }
    #if defined(__BIONIC__)  // 使用了bionic
        const prop_info* prop = __system_property_find(key.c_str());//获取key对应的prop info
        if (!prop) {
            return;
        }
        ReadProperty(prop, std::forward<Functor>(functor)); // 读取value
    #else
        std::forward<Functor>(functor)(
            android::base::GetProperty(key.c_str(), "").c_str());
    #endif
    }
    
    // 调用另一个 ReadProperty 函数
    template<typename Functor>
    void ReadProperty(const prop_info* prop, Functor&& functor)
    {
    #if defined(__BIONIC__)
        auto thunk = [](void* cookie,
                        const char* /*name*/,
                        const char* value,
                        uint32_t /*serial*/) {
            std::forward<Functor>(*static_cast<Functor*>(cookie))(value); // 回调 Functor
        };
        __system_property_read_callback(prop, thunk, &functor); // 读取value并回调
    #else
        LOG(FATAL) << "fast property access supported only on device";
    #endif
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    __system_property_find

    /// @bionic/libc/bionic/system_property_api.cpp
    __BIONIC_WEAK_FOR_NATIVE_BRIDGE
    const prop_info* __system_property_find(const char* name) {
      return system_properties.Find(name); // 寻找name对应context的映射区域内的prop信息
    }
    
    /// @bionic/libc/system_properties/system_properties.cpp
    const prop_info* SystemProperties::Find(const char* name) {
      if (!initialized_) {// 未初始化则返回
        return nullptr;
      }
    
      prop_area* pa = contexts_->GetPropAreaForName(name); // 找到name对应的映射区
      if (!pa) {
        async_safe_format_log(ANDROID_LOG_WARN, "libc", "Access denied finding property \"%s\"", name);
        return nullptr;
      }
    
      return pa->find(name); // 从这个区域寻找对应的属性信息
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    ContextsSerialized::GetPropAreaForName

    prop_area* ContextsSerialized::GetPropAreaForName(const char* name) {
      uint32_t index;
      property_info_area_file_->GetPropertyInfoIndexes(name, &index, nullptr);// 根据name获取context在集合中的index
      if (index == ~0u || index >= num_context_nodes_) {
        async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Could not find context for property \"%s\"",
                              name);
        return nullptr;
      }
      auto* context_node = &context_nodes_[index]; // 获取name对应的 context_node
      if (!context_node->pa()) { // 如果还没映射该节点
        // We explicitly do not check no_access_ in this case because unlike the
        // case of foreach(), we want to generate an selinux audit for each
        // non-permitted property access in this function.
        context_node->Open(false, nullptr); // 需要映射此节点,注意第一个参数为false,只读
      }
      return context_node->pa(); // 返回映射区域
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    如之前,在ContextNode::Open中传入参数为false,会调用prop_area::map_prop_area映射到内存

    prop_area* prop_area::map_prop_area(const char* filename) {
      int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY); //只读方式打开
      if (fd == -1) return nullptr;
    
      prop_area* map_result = map_fd_ro(fd); // 只读映射到内存
      close(fd);
    
      return map_result;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    __system_property_read_callback

    此处上面的callback是上面传过来的thunk,cookie 是传的Functor

    /// @bionic/libc/bionic/system_property_api.cpp
    __BIONIC_WEAK_FOR_NATIVE_BRIDGE
    void __system_property_read_callback(const prop_info* pi,
                                         void (*callback)(void* cookie, const char* name,
                                                          const char* value, uint32_t serial),
                                         void* cookie) {
      return system_properties.ReadCallback(pi, callback, cookie);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    SystemProperties::ReadCallback

    /// @bionic/libc/system_properties/system_properties.cpp
    void SystemProperties::ReadCallback(const prop_info* pi,
                                        void (*callback)(void* cookie, const char* name,
                                                         const char* value, uint32_t serial),
                                        void* cookie) {
      // Read only properties don't need to copy the value to a temporary buffer, since it can never
      // change.  We use relaxed memory order on the serial load for the same reason.
      if (is_read_only(pi->name)) { // ro. 只读属性,value不会改变
        uint32_t serial = load_const_atomic(&pi->serial, memory_order_relaxed);
        if (pi->is_long()) {
          callback(cookie, pi->name, pi->long_value(), serial);
        } else {
          callback(cookie, pi->name, pi->value, serial);
        }
        return;
      }
    
      char value_buf[PROP_VALUE_MAX];
      uint32_t serial = ReadMutablePropertyValue(pi, value_buf); // 读取可变的属性值
      callback(cookie, pi->name, value_buf, serial); // 回调获取得到值
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    SystemProperties::ReadMutablePropertyValue

    #define	__predict_true(exp)	__builtin_expect((exp) != 0, 1)
    #define	__predict_false(exp)	__builtin_expect((exp) != 0, 0)
    
    uint32_t SystemProperties::ReadMutablePropertyValue(const prop_info* pi, char* value) {
      // We assume the memcpy below gets serialized by the acquire fence.
      uint32_t new_serial = load_const_atomic(&pi->serial, memory_order_acquire);
      uint32_t serial;
      unsigned int len;
      for (;;) {
        serial = new_serial;
        len = SERIAL_VALUE_LEN(serial);
        if (__predict_false(SERIAL_DIRTY(serial))) { // 检测到数据有更新
          // See the comment in the prop_area constructor.
          prop_area* pa = contexts_->GetPropAreaForName(pi->name);
          memcpy(value, pa->dirty_backup_area(), len + 1);
        } else {
          memcpy(value, pi->value, len + 1); // 拷贝value数据
        }
        atomic_thread_fence(memory_order_acquire);
        new_serial = load_const_atomic(&pi->serial, memory_order_relaxed);
        if (__predict_true(serial == new_serial)) { // 没有数据改变,跳出
          break;
        }
        // We need another fence here because we want to ensure that the memcpy in the
        // next iteration of the loop occurs after the load of new_serial above. We could
        // get this guarantee by making the load_const_atomic of new_serial
        // memory_order_acquire instead of memory_order_relaxed, but then we'd pay the
        // penalty of the memory_order_acquire even in the overwhelmingly common case
        // that the serial number didn't change.
        atomic_thread_fence(memory_order_acquire);
      }
      return serial;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    总结一下ReadProperty获取属性的流程

    • __system_property_find 寻找prop_info
      • 获取key对应的ContextNode的内存映射区域prop_area
      • 如果节点没有,则会打开并以只读映射到内存
      • 从prop_area中读取prop_info
    • __system_property_read_callback 从prop info获取value,并回传value值
      • 从prop_info中读取value
      • callback回调传回value值

    在上面SystemProperties::Find中,如果initialized_为false则返回,那么什么时候进行初始化呢?对于Android中的应用或native程序而言,它在启动时会首先加载linker模块做一些初始化,其中就包括属性初始化,主要看linker_main函数

    linker_main

    /// bionic/linker/linker_main.cpp
    static ElfW(Addr) linker_main(KernelArgumentBlock& args, const char* exe_to_load) {
      ...
      // Initialize system properties
      // 此处做初始化
      __system_properties_init(); // may use 'environ'
    
      // Initialize platform properties.
      platform_properties_init();
    
      // Register the debuggerd signal handler.
      linker_debuggerd_init(); // 初始化 signal handler
      ...
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    __system_properties_init

    /// @bionic/libc/bionic/system_property_api.cpp
    __BIONIC_WEAK_FOR_NATIVE_BRIDGE
    int __system_properties_init() {// PROP_FILENAME 是 /dev/__properties__
      return system_properties.Init(PROP_FILENAME) ? 0 : -1;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    SystemProperties::Init

    /// @bionic/libc/system_properties/system_properties.cpp
    bool SystemProperties::Init(const char* filename) {
      // This is called from __libc_init_common, and should leave errno at 0 (http://b/37248982).
      ErrnoRestorer errno_restorer;
    
      if (initialized_) {
        contexts_->ResetAccess();
        return true;
      }
    
      if (strlen(filename) >= PROP_FILENAME_MAX) {
        return false;
      }
      strcpy(property_filename_, filename);
    
      if (is_dir(property_filename_)) { // 判断是目录,已在init中创建
        // property_info 可读,创建 ContextsSerialized 并初始化
        if (access("/dev/__properties__/property_info", R_OK) == 0) {
          contexts_ = new (contexts_data_) ContextsSerialized();
          if (!contexts_->Initialize(false, property_filename_, nullptr)) {
            return false;
          }
        } else { // 否则创建 ContextsSplit 并初始化
          contexts_ = new (contexts_data_) ContextsSplit 并初始化();
          if (!contexts_->Initialize(false, property_filename_, nullptr)) {
            return false;
          }
        }
      } else { // 否则创建 ContextsPreSplit 并初始化
        contexts_ = new (contexts_data_) ContextsPreSplit();
        if (!contexts_->Initialize(false, property_filename_, nullptr)) {
          return false;
        }
      }
      initialized_ = true; // 标记已初始化
      return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    以ContextsSerialized的初始化为例

    /// @bionic/libc/system_properties/contexts_serialized.cpp
    bool ContextsSerialized::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) {
      filename_ = filename;
      if (!InitializeProperties()) {
        return false;
      }
      // 从上面传递的writable值为false
      if (writable) { // 在init中走这个逻辑
        mkdir(filename_, S_IRWXU | S_IXGRP | S_IXOTH);
        bool open_failed = false;
        if (fsetxattr_failed) {
          *fsetxattr_failed = false;
        }
    
        for (size_t i = 0; i < num_context_nodes_; ++i) {
          if (!context_nodes_[i].Open(true, fsetxattr_failed)) {// 打开各个节点
            open_failed = true;
          }
        }
        if (open_failed || !MapSerialPropertyArea(true, fsetxattr_failed)) { // 对
          FreeAndUnmap();
          return false;
        }
      } else { // 走这个逻辑,将 properties_serial 映射到内存
        if (!MapSerialPropertyArea(false, nullptr)) {
          FreeAndUnmap();
          return false;
        }
      }
      return true;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    从上面分析看,只是将properties_serial映射到了内存,而并没有映射其他ContextNode对应的文件节点。

    设置属性流程

    接下来,以 SystemProperties#set 设置属性来分析该流程。

    SystemProperties#set

    /// @frameworks/base/core/java/android/os/SystemProperties.java
    /**
     * Set the value for the given {@code key} to {@code val}.
     *
     * @throws IllegalArgumentException if the {@code val} exceeds 91 characters
     * @throws RuntimeException if the property cannot be set, for example, if it was blocked by
     * SELinux. libc will log the underlying reason.
     * @hide
     */
    @UnsupportedAppUsage
    public static void set(@NonNull String key, @Nullable String val) {
        if (val != null && !val.startsWith("ro.") && val.length() > PROP_VALUE_MAX) {
            throw new IllegalArgumentException("value of system property '" + key
                    + "' is longer than " + PROP_VALUE_MAX + " characters: " + val);
        }
        if (TRACK_KEY_ACCESS) onKeyAccess(key);
        native_set(key, val); // 对应native方法
    }
    
    // _NOT_ FastNative: native_set performs IPC and can block
    @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P)
    private static native void native_set(String key, String def); // 跨进程可能阻塞,不能是FastNative
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    SystemProperties_set

    native_set 对应的jni函数是 SystemProperties_set

    /// @frameworks/base/core/jni/android_os_SystemProperties.cpp
    { "native_set", "(Ljava/lang/String;Ljava/lang/String;)V",
      (void*) SystemProperties_set },
    
      void SystemProperties_set(JNIEnv *env, jobject clazz, jstring keyJ,
                                jstring valJ)
      {
          ScopedUtfChars key(env, keyJ); // 封装,将jstring转char*
          if (!key.c_str()) {
              return;
          }
          std::optional<ScopedUtfChars> value;
          if (valJ != nullptr) {
              value.emplace(env, valJ);
              if (!value->c_str()) {
                  return;
              }
          }
          bool success;
      #if defined(__BIONIC__)  // android 定义了 __BIONIC__
          success = !__system_property_set(key.c_str(), value ? value->c_str() : "");
      #else
          success = android::base::SetProperty(key.c_str(), value ? value->c_str() : "");
      #endif
          if (!success) {
              jniThrowException(env, "java/lang/RuntimeException",
                                "failed to set system property (check logcat for reason)");
          }
      }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    __system_property_set

    /// @bionic/libc/bionic/system_property_set.cpp
    __BIONIC_WEAK_FOR_NATIVE_BRIDGE
    int __system_property_set(const char* key, const char* value) {
      if (key == nullptr) return -1;
      if (value == nullptr) value = "";
    
      if (g_propservice_protocol_version == 0) { // 默认为0,需要获取协议版本
        detect_protocol_version();
      }
    
      if (g_propservice_protocol_version == kProtocolVersion1) { // 老协议,使用 PROP_MSG_SETPROP
        // Old protocol does not support long names or values
        if (strlen(key) >= PROP_NAME_MAX) return -1;
        if (strlen(value) >= PROP_VALUE_MAX) return -1;
    
        prop_msg msg;
        memset(&msg, 0, sizeof msg);
        msg.cmd = PROP_MSG_SETPROP;
        strlcpy(msg.name, key, sizeof msg.name);
        strlcpy(msg.value, value, sizeof msg.value);
    
        return send_prop_msg(&msg);
      } else { // 新协议,使用 PROP_MSG_SETPROP2
        // New protocol only allows long values for ro. properties only.
        if (strlen(value) >= PROP_VALUE_MAX && strncmp(key, "ro.", 3) != 0) return -1;
        // Use proper protocol
        PropertyServiceConnection connection; // 连接属性服务的socket服务端
        if (!connection.IsValid()) {
          errno = connection.GetLastError();
          async_safe_format_log(
              ANDROID_LOG_WARN, "libc",
              "Unable to set property \"%s\" to \"%s\": connection failed; errno=%d (%s)", key, value,
              errno, strerror(errno));
          return -1;
        }
    
        SocketWriter writer(&connection); // 传给SocketWriter,用它来进行读写
        // 向 init 属性服务 server socket 写入属性键值
        if (!writer.WriteUint32(PROP_MSG_SETPROP2).WriteString(key).WriteString(value).Send()) {
          errno = connection.GetLastError();
          async_safe_format_log(ANDROID_LOG_WARN, "libc",
                                "Unable to set property \"%s\" to \"%s\": write failed; errno=%d (%s)",
                                key, value, errno, strerror(errno));
          return -1;
        }
    
        int result = -1;
        // 读取服务端的回复
        if (!connection.RecvInt32(&result)) {
          errno = connection.GetLastError();
          async_safe_format_log(ANDROID_LOG_WARN, "libc",
                                "Unable to set property \"%s\" to \"%s\": recv failed; errno=%d (%s)",
                                key, value, errno, strerror(errno));
          return -1;
        }
    
        if (result != PROP_SUCCESS) { // 不成功,打印失败log
          async_safe_format_log(ANDROID_LOG_WARN, "libc",
                                "Unable to set property \"%s\" to \"%s\": error code: 0x%x", key, value,
                                result);
          return -1;
        }
    
        return 0;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66

    detect_protocol_version

    #define PROP_SERVICE_NAME "property_service"
    #define PROP_FILENAME "/dev/__properties__"
    
    /// @bionic/libc/bionic/system_property_set.cpp
    static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
    static const char* kServiceVersionPropertyName = "ro.property_service.version";
    
    static constexpr uint32_t kProtocolVersion1 = 1;
    static constexpr uint32_t kProtocolVersion2 = 2;  // current
    static atomic_uint_least32_t g_propservice_protocol_version = 0;
    
    static void detect_protocol_version() {
      char value[PROP_VALUE_MAX];
      // 获取属性服务版本
      if (__system_property_get(kServiceVersionPropertyName, value) == 0) {
        g_propservice_protocol_version = kProtocolVersion1; // 为0,默认使用协议1
        async_safe_format_log(ANDROID_LOG_WARN, "libc",
                              "Using old property service protocol (\"%s\" is not set)",
                              kServiceVersionPropertyName);
      } else { // 否则使用获取的版本
        uint32_t version = static_cast<uint32_t>(atoll(value));
        if (version >= kProtocolVersion2) { // 协议2
          g_propservice_protocol_version = kProtocolVersion2;
        } else {  // 协议1
          async_safe_format_log(ANDROID_LOG_WARN, "libc",
                                "Using old property service protocol (\"%s\"=\"%s\")",
                                kServiceVersionPropertyName, value);
          g_propservice_protocol_version = kProtocolVersion1;
        }
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    从机器获取的属性值是2,也就是当前使用的是协议2

    $ getprop ro.property_service.version                                                                                          
    2
    
    • 1
    • 2

    建立socket连接

    在PropertyServiceConnection的构造函数中,建立与属性服务端socket的连接。

    PropertyServiceConnection() : last_error_(0) {
      socket_.reset(::socket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0));// 创建client socket
      if (socket_.get() == -1) {
        last_error_ = errno;
        return;
      }
    
      const size_t namelen = strlen(property_service_socket);
      sockaddr_un addr;
      memset(&addr, 0, sizeof(addr));
      strlcpy(addr.sun_path, property_service_socket, sizeof(addr.sun_path));
      addr.sun_family = AF_LOCAL;
      socklen_t alen = namelen + offsetof(sockaddr_un, sun_path) + 1;
      // 连接 server socket
      if (TEMP_FAILURE_RETRY(connect(socket_.get(),
                                     reinterpret_cast<sockaddr*>(&addr), alen)) == -1) {
        last_error_ = errno;
        socket_.reset();
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    写属性

    class SocketWriter {
     public:
      explicit SocketWriter(PropertyServiceConnection* connection)
          : connection_(connection), iov_index_(0), uint_buf_index_(0) {
      }
      // 写 uint32_t 数据
      SocketWriter& WriteUint32(uint32_t value) {
        CHECK(uint_buf_index_ < kUintBufSize);
        CHECK(iov_index_ < kIovSize);
        uint32_t* ptr = uint_buf_ + uint_buf_index_;
        uint_buf_[uint_buf_index_++] = value;
        iov_[iov_index_].iov_base = ptr;
        iov_[iov_index_].iov_len = sizeof(*ptr);
        ++iov_index_;
        return *this;
      }
      // 写 字符串 数据
      SocketWriter& WriteString(const char* value) {
        uint32_t valuelen = strlen(value);
        WriteUint32(valuelen);
        if (valuelen == 0) {
          return *this;
        }
    
        CHECK(iov_index_ < kIovSize);
        iov_[iov_index_].iov_base = const_cast<char*>(value);
        iov_[iov_index_].iov_len = valuelen;
        ++iov_index_;
    
        return *this;
      }
      // 发送数据给server端
      bool Send() {
        if (!connection_->IsValid()) {
          return false;
        }
    
        if (writev(connection_->socket(), iov_, iov_index_) == -1) {
          connection_->last_error_ = errno;
          return false;
        }
    
        iov_index_ = uint_buf_index_ = 0;
        return true;
      }
    
     private:
      ...
      BIONIC_DISALLOW_IMPLICIT_CONSTRUCTORS(SocketWriter);
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    读回复

    class PropertyServiceConnection {
    public:
      ...
      // 读取 int32_t 数据
      bool RecvInt32(int32_t* value) {
        int result = TEMP_FAILURE_RETRY(recv(socket_.get(), value, sizeof(*value), MSG_WAITALL));
        return CheckSendRecvResult(result, sizeof(*value));
      }
    
    private:
      bool CheckSendRecvResult(int result, int expected_len) { // 检查结果是否错误
        if (result == -1) {
          last_error_ = errno;
        } else if (result != expected_len) {
          last_error_ = -1;
        } else {
          last_error_ = 0;
        }
    
        return last_error_ == 0;
      }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    当init属性服务收到客户端收到的设置属性请求后,会回调handle_property_set_fd函数来处理请求,可以参照之前的分析。

    总结

    • init初始化属性内存区域,根据每个property context创建对应的ContextNode,建立节点文件并以读写映射到内存
    • init从各个build.prop文件中加载属性值
    • init启动属性服务,创建服务端socket,等待客户端连接来设置属性
    • 客户端通过socket连接属性服务端socket,通过socket写数据来设置属性值
    • 客户端通过打开节点文件并以只读映射到内存,然后读取对应的属性值
  • 相关阅读:
    【安卓app毕业设计源码】基于Uniapp的掌上校园管理系统
    Spring简介
    通俗易懂玩QT:QT程序发布打包
    Spring(五):Spring Boot 的配置和日志
    猫爪插件-官网下载方法
    LeetCode(力扣)134. 加油站Python
    回 溯 法
    shell 实现对Hive表字段脱敏写入新表
    什么是物联网(IoT)?
    Linux内核数据管理利器--红黑树
  • 原文地址:https://blog.csdn.net/qq_28261343/article/details/128124518