Android属性服务——初始化

前言

在Android系统开发或者App开发中,经常会用到属性服务,通过一些系统属性来做数据的传递、控制等。从本系列来剖析下Android的属性服务是如何工作的,本篇先介绍第一篇,属性服务的初始化。分析源码为Android11,部分章节有对比Android12的变更。

启动入口

Android启动流程和原理分析二_Cheson_chen的博客-CSDN博客中有提到了Init的初始化流程,属性服务呢就是在Init初始化的第二个阶段去启动的。

system/core/init/init.cpp

int SecondStageMain(int argc, char** argv) {
	...
	PropertyInit();
	...
	StartPropertyService(&property_fd);
	...
}

属性初始化PropertyInit

system/core/init/property_service.cpp

void PropertyInit() {
		//1.注册selinux audit事件的回调
    selinux_callback cb;
    cb.func_audit = PropertyAuditCallback;
    selinux_set_callback(SELINUX_CB_AUDIT, cb);
		//2.创建/dev/__properties__目录,
    mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
		//3.写入序列化属性信息
    CreateSerializedPropertyInfo();
    if (__system_property_area_init()) {//4.初始化属性域共享内存
        LOG(FATAL) << "Failed to initialize property area";
    }
    if (!property_info_area.LoadDefaultPath()) {//5.再走一次加载
        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.
		//6.处理设备树和kernel的启动cmd
    ProcessKernelDt();
    ProcessKernelCmdline();

    // Propagate the kernel variables to internal variables
    // used by init as well as the current required properties.
		//7.kernel启动属性初始化
    ExportKernelBootProps();
		//8.加载默认属性
    PropertyLoadBootDefaults();
}

1.注册selinux audit事件的回调

通过selinux_set_callback来设置了一个SELINUX_CB_AUDIT类型的callback,callback处理的函数为PropertyAuditCallback。

system/core/init/property_service.cpp

static int PropertyAuditCallback(void* data, security_class_t /*cls*/, char* buf, size_t len) {
    auto* d = reinterpret_cast<PropertyAuditData*>(data);

    if (!d || !d->name || !d->cr) {
        LOG(ERROR) << "AuditCallback invoked with null data arguments!";
        return 0;
    }

    snprintf(buf, len, "property=%s pid=%d uid=%d gid=%d", d->name, d->cr->pid, d->cr->uid,
             d->cr->gid);
    return 0;
}

2.创建属性服务的存储目录

后面用于属性服务内容的存储位置,权限为711

3.写入序列化属性信息

system/core/init/property_service.cpp

void CreateSerializedPropertyInfo() {
		//1.把几个文件中的属性+selinux policy的内容都加载到PropertyInfo中
    auto property_infos = std::vector<PropertyInfoEntry>();
    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, so we always have a sane list of properties.
        // 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);
    }
		//2.做字典排序,存入到serialized_contexts中
    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;
    }
		//3.将serialized_contexts写入到/dev/__properties__/property_info中
    constexpr static const char kPropertyInfosPath[] = "/dev/__properties__/property_info";
    if (!WriteStringToFile(serialized_contexts, kPropertyInfosPath, 0444, 0, 0, false)) {
        PLOG(ERROR) << "Unable to write serialized property infos to file";
    }
		//4.在kPropertyInfosPath文件更改之后,恢复该文件的SELinux上下文,确保系统安全和完整
    selinux_android_restorecon(kPropertyInfosPath, 0);
}

 4.初始化属性域共享内存

bionic/libc/bionic/system_property_api.cpp

__BIONIC_WEAK_FOR_NATIVE_BRIDGE
int __system_property_area_init() {
  bool fsetxattr_failed = false;
	//1.这里的PROP_FILENAME就是在ProPerty_Init中创建的目录/dev/__properties__
  return system_properties.AreaInit(PROP_FILENAME, &fsetxattr_failed) && !fsetxattr_failed ? 0 : -1;
}

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);
	//2.处理文件名之后,调用ContextsSerialized类的Initialize方法
  contexts_ = new (contexts_data_) ContextsSerialized();
  if (!contexts_->Initialize(true, property_filename_, fsetxattr_failed)) {
    return false;
  }
  initialized_ = true;
  return true;
}

bionic/libc/system_properties/contexts_serialized.cpp

bool ContextsSerialized::Initialize(bool writable, const char* filename, bool* fsetxattr_failed) {
  filename_ = filename;
	//1.调用InitializeProperties
  if (!InitializeProperties()) {
    return false;
  }

  if (writable) {
    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 {
    if (!MapSerialPropertyArea(false, nullptr)) {
      FreeAndUnmap();
      return false;
    }
  }
  return true;
}

先是调用InitializeProperties

bionic/libc/system_properties/contexts_serialized.cpp

bool ContextsSerialized::InitializeProperties() {
	//1.加载
  if (!property_info_area_file_.LoadDefaultPath()) {
    return false;
  }

  if (!InitializeContextNodes()) {
    FreeAndUnmap();
    return false;
  }

  return true;
}

bionic/libc/system_properties/contexts_serialized.cpp

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

然后做InitializeContextNodes

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;

  for (size_t i = 0; i < num_context_nodes; ++i) {
    new (&context_nodes_[i]) ContextNode(property_info_area_file_->context(i), filename_);
  }

  return true;
}

主要做的就是把内存中的初始化属性和sepolicy策略加载成ContextNode的形式。

5.加载默认配置

property_info_area.LoadDefaultPath()这个调用很奇怪,在第四步中其实也有调用过这个流程,这里为什么还要再调用一次呢?

6.处理设备树和kernel的启动cmd

system/core/init/property_service.cpp

static void ProcessKernelDt() {
    if (!is_android_dt_value_expected("compatible", "android,firmware")) {
        return;
    }

    std::unique_ptr<DIR, int (*)(DIR*)> dir(opendir(get_android_dt_dir().c_str()), closedir);
    if (!dir) return;

    std::string dt_file;
    struct dirent* dp;
    while ((dp = readdir(dir.get())) != NULL) {
        LOG(ERROR) << "dongqichen: ProcessKernelDt d_name " << dp->d_name;
        if (dp->d_type != DT_REG || !strcmp(dp->d_name, "compatible") ||
            !strcmp(dp->d_name, "name")) {
            continue;
        }

        std::string file_name = get_android_dt_dir() + dp->d_name;

        android::base::ReadFileToString(file_name, &dt_file);
        LOG(ERROR) << "dongqichen: ProcessKernelDt file_name " << file_name << ", dt_file " << dt_file;
        std::replace(dt_file.begin(), dt_file.end(), ',', '.');

        InitPropertySet("ro.boot." + dp->d_name, dt_file);
    }
}

system/core/init/property_service.cpp 

static void ProcessKernelCmdline() {
    bool for_emulator = false;
    ImportKernelCmdline([&](const std::string& key, const std::string& value) {
        if (key == "qemu") {
            for_emulator = true;
        } else if (StartsWith(key, "androidboot.")) {
            InitPropertySet("ro.boot." + key.substr(12), value);
        }
    });

    if (for_emulator) {
        ImportKernelCmdline([&](const std::string& key, const std::string& value) {
            // In the emulator, export any kernel option with the "ro.kernel." prefix.
            InitPropertySet("ro.kernel." + key, value);
        });
    }
}

这里的逻辑就是从启动命令中读取到androidboot开头的属性,将其value,作为初始化设置到ro.boot中去。如果是模拟器则会设置到ro.kernel中。这部分代码在Android12上做了调整。

system/core/init/property_service.cpp

static void ProcessKernelCmdline() {
    ImportKernelCmdline([&](const std::string& key, const std::string& value) {
        LOG(ERROR) << "dongqichen: ProcessKernelCmdline key " << key << ", value " << value;
        if (StartsWith(key, ANDROIDBOOT_PREFIX)) {
            InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
        }
    });
}


static void ProcessBootconfig() {
    ImportBootconfig([&](const std::string& key, const std::string& value) {
        LOG(ERROR) << "dongqichen: ProcessBootconfig key " << key << ", value " << value;
        if (StartsWith(key, ANDROIDBOOT_PREFIX)) {
            InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
        }
    });
}

在PropertyInit中调用了上面两个函数

ImportKernelCmdline这个函数是通过读设备节点来读到启动命令的

system/core/init/util.cpp

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]);
        }
    }
}

ImportBootconfig是从/proc/bootconfig读取的,我是在Android12的Car模拟器上看的

adb shell cat /proc/cmdline

stack_depot_disable=on cgroup_disable=pressure cgroup.memory=nokmem no_timer_check clocksource=pit console=0 cma=266M@0-4G loop.max_part=7 ramoops.mem_address=0xff018000 ramoops.mem_size=0x10000 memmap=0x10000$0xff018000 printk.devkmsg=on bootconfig mac80211_hwsim.radios=0

system/core/init/util.cpp

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));
        }
    }
}

adb shell cat /proc/bootconfig

androidboot.qemu = "1"
androidboot.qemu.cpuvulkan.version = "4202496"
androidboot.qemu.settings.system.screen_off_timeout = "1800000"
androidboot.qemu.vsync = "60"
androidboot.qemu.gltransport.name = "pipe"
androidboot.qemu.gltransport.drawFlushInterval = "800"
androidboot.qemu.adb.pubkey = "QAAAAN34PfKLYDNTo4z6UolMKOsGh6bUf1WWsASBOXYaxS7xhsLQSlO8vZjrzIe+9xz4Mj6/F2EPOaXRUbn4y6BwNFwPF0Nj0gehghtqTep84/aVm5sSeGcBup78jlma+3hSEnfx2AYs4EWQuY1Ik6ub+w7dezQsM+5suSvFQukxLA2Ts9FL8eH/ntfnk3EbiRlegb6Ql9g4WDt3VDwK8zEo75thh+ejDt1AiCZEjH44ySSBb/Z8a/tmwygJVCzYvuPiqYLAsiwy4sLKRdPca6nCD/1daRIhnINur0/OUmoe7ZeSUVzqR9hjMPh8LeFaHgVxdH/PGa9sPX7pTR3kYNZQIqmYzhC+5LP3tHx0VERBnk671l7OaXltnRBZj9yAKbHXQi6PKtZEWf/8UVYuzNrgvYvUpvbwW6LzQVQ6KvlHpyIWaWhbdV4jfjeKWdLqcLzOPwSwFoN93Q8qBZ79snYkZaivEf0feiSR+Jy1o0bIxSPbTM4KJ73EvPLVHiYwHQIaygzARwCMQurEUnl+g/W5WL6GMAeoSO8BjgdzcK0qnbN8Gg4iLSo/wyROTYA8npyWm+N0V9iXemi68pRqtaKM4F+DitGkBAh2Nsn5F7lTLyeUqS8St37BRsiO++mndApLVsLzlIClFIPHsazTAhhCK6NwamzkR86kMREXXNVZ8m8NkVmigAEAAQA= ecarx@unknown"
androidboot.qemu.camera_protocol_ver = "1"
androidboot.qemu.camera_hq_edge_processing = "0"
androidboot.qemu.virtiowifi = "1"
androidboot.qemu.hwcodec.avcdec = "2"
androidboot.qemu.hwcodec.vpxdec = "2"
androidboot.qemu.avd_name = "<build>"
androidboot.hardware = "ranchu"
androidboot.serialno = "EMULATOR31X3X5X0"
androidboot.veritymode = "enforcing"
androidboot.opengles.version = "196609"
androidboot.debug.hwui.renderer = "skiagl"
androidboot.logcat = "*:V"
androidboot.dalvik.vm.heapsize = "512m"
androidboot.vbmeta.size = "6272"
androidboot.vbmeta.hash_alg = "sha256"
androidboot.vbmeta.digest = "1a5a951f2a5ac4245b2a30c9dfac8393294c0d26960cebc948d8910e15d745a4"
androidboot.boot_devices = "pci0000:00/0000:00:03.0"

7.kernel启动属性初始化

system/core/init/property_service.cpp

static void ExportKernelBootProps() {
    constexpr const char* UNSET = "";
    struct {
        const char* src_prop;
        const char* dst_prop;
        const char* default_value;
    } prop_map[] = {
            // clang-format off
        { "ro.boot.serialno",   "ro.serialno",   UNSET, },
        { "ro.boot.mode",       "ro.bootmode",   "unknown", },
        { "ro.boot.baseband",   "ro.baseband",   "unknown", },
        { "ro.boot.bootloader", "ro.bootloader", "unknown", },
        { "ro.boot.hardware",   "ro.hardware",   "unknown", },
        { "ro.boot.revision",   "ro.revision",   "0", },
            // clang-format on
    };
    for (const auto& prop : prop_map) {
        std::string value = GetProperty(prop.src_prop, prop.default_value);
        if (value != UNSET) InitPropertySet(prop.dst_prop, value);
    }
}

这个函数的逻辑就是定义了一组ro.boot属性的value读出来,设置到对应的ro属性中。如将ro.boot.serialno的value设置到ro.serialno中。

8.加载默认属性

system/core/init/property_service.cpp

void PropertyLoadBootDefaults() {
    // TODO(b/117892318): merge prop.default and build.prop files into one
    // 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 (!load_properties_from_file("/system/etc/prop.default", nullptr, &properties)) {
        // Try recovery path
        if (!load_properties_from_file("/prop.default", nullptr, &properties)) {
            // Try legacy path
            load_properties_from_file("/default.prop", nullptr, &properties);
        }
    }
    load_properties_from_file("/system/build.prop", nullptr, &properties);
    load_properties_from_file("/system_ext/build.prop", nullptr, &properties);
    load_properties_from_file("/vendor/default.prop", nullptr, &properties);
    load_properties_from_file("/vendor/build.prop", nullptr, &properties);
    if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) {
        load_properties_from_file("/odm/etc/build.prop", nullptr, &properties);
    } else {
        load_properties_from_file("/odm/default.prop", nullptr, &properties);
        load_properties_from_file("/odm/build.prop", nullptr, &properties);
    }
    load_properties_from_file("/product/build.prop", nullptr, &properties);
    load_properties_from_file("/factory/factory.prop", "ro.*", &properties);

    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;
        }
    }
		//以上就是把一些.prop文件中的属性定义读取到properties中,然后设置成属性
	
    property_initialize_ro_product_props();
    property_derive_build_fingerprint();

    update_sys_usb_config();
}

property_initialize_ro_product_props这个方法做的事情是初始化ro.product.*这一类的属性,如果没有被初始化过,那么就集成partition的属性。例如ro.product.brand没有初始化,那么就集成ro.product.system.brand,也就是Android。

property_derive_build_fingerprint这个函数是在做fingerprint属性的初始化,如果没有初始化那就用brand、name、device、release、id、incremental、type、tags这些来拼接。

update_sys_usb_config这个方法是用来更新persist.sys.usb.config属性的,根据ro.debuggable这个属性来动态设置,这个决定了设备是否允许adb调试,项目要禁用adb可以参考这个属性。

属性服务启动

system/core/init/property_service.cpp

void StartPropertyService(int* epoll_socket) {
		//1.设置属性服务版本为2
    InitPropertySet("ro.property_service.version", "2");
		//2.构造socket
    int sockets[2];
    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_socket = sockets[1];
    StartSendingMessages();
		//3.创建socket
    if (auto result = CreateSocket(PROP_SERVICE_NAME, SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK,
                                   false, 0666, 0, 0, {});
        result.ok()) {
        property_set_fd = *result;
    } else {
        LOG(FATAL) << "start_property_service socket creation failed: " << result.error();
    }
		//监听通讯,最大数量为8
    listen(property_set_fd, 8);
		//4.创建PropertyServiceThread来作为执行线程
    auto new_thread = std::thread{PropertyServiceThread};
    property_service_thread.swap(new_thread);
}

1.设置属性服务版本

在Android11代码中版本为2,这个在处理属性设置时会用版本号去判断处理逻辑,做了新旧版本的代码兼容。

2.构造socket

构造了一对UNIX套接字,用于属性服务和init之间的双工通讯。

3.创建socket

PROP_SERVICE_NAME定义为property_service

4.创建执行线程

PropertyServiceThread作为执行线程
system/core/init/property_service.cpp

static void PropertyServiceThread() {
    Epoll epoll;
    if (auto result = epoll.Open(); !result.ok()) {
        LOG(FATAL) << result.error();
    }

    if (auto result = epoll.RegisterHandler(property_set_fd, handle_property_set_fd);
        !result.ok()) {
        LOG(FATAL) << result.error();
    }

    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)();
            }
        }
    }
}

在epoll中注册了socket通讯的处理函数,如果是property_set_fd则走到handle_property_set_fd来处理,这个就是设置属性时会走的流程;如果是init_socket,则会走HandleInitSocket,这个是初始化的流程。

然后PropertyServiceThread就陷入了死循环处理epoll事件了。

初始化消息处理

在接收到init_socket之后,会转到HandleInitSocket处理

system/core/init/property_service.cpp

static void HandleInitSocket() {
    auto message = ReadMessage(init_socket);
    if (!message.ok()) {
        LOG(ERROR) << "Could not read message from init_dedicated_recv_socket: " << message.error();
        return;
    }

    auto init_message = InitMessage{};
    if (!init_message.ParseFromString(*message)) {
        LOG(ERROR) << "Could not parse message from init";
        return;
    }

    switch (init_message.msg_case()) {
        case InitMessage::kLoadPersistentProperties: {
            load_override_properties();
            // Read persistent properties after all default values have been loaded.
            auto persistent_properties = LoadPersistentProperties();
            for (const auto& persistent_property_record : persistent_properties.properties()) {
                InitPropertySet(persistent_property_record.name(),
                                persistent_property_record.value());
            }
            InitPropertySet("ro.persistent_properties.ready", "true");
            persistent_properties_loaded = true;
            break;
        }
        default:
            LOG(ERROR) << "Unknown message type from init: " << init_message.msg_case();
    }
}

前面都是读socket的消息,重点的内容是加载persist属性,这也就是为什么persist属性可以在重启后保持,因为有这个开机去load的过程。

system/core/init/persistent_properties.cpp

PersistentProperties LoadPersistentProperties() {
    auto persistent_properties = LoadPersistentPropertyFile();

    if (!persistent_properties.ok()) {
        LOG(ERROR) << "Could not load single persistent property file, trying legacy directory: "
                   << persistent_properties.error();
        persistent_properties = LoadLegacyPersistentProperties();
        if (!persistent_properties.ok()) {
            LOG(ERROR) << "Unable to load legacy persistent properties: "
                       << persistent_properties.error();
            return {};
        }
        if (auto result = WritePersistentPropertyFile(*persistent_properties); result.ok()) {
            RemoveLegacyPersistentPropertyFiles();
        } else {
            LOG(ERROR) << "Unable to write single persistent property file: " << result.error();
            // Fall through so that we still set the properties that we've read.
        }
    }

    return *persistent_properties;
}

通过LoadPersistentPropertyFile加载文件

system/core/init/persistent_properties.cpp

Result<PersistentProperties> LoadPersistentPropertyFile() {
    auto file_contents = ReadPersistentPropertyFile();
    if (!file_contents.ok()) return file_contents.error();

    PersistentProperties persistent_properties;
    if (persistent_properties.ParseFromString(*file_contents)) return persistent_properties;

    // If the file cannot be parsed in either format, then we don't have any recovery
    // mechanisms, so we delete it to allow for future writes to take place successfully.
    unlink(persistent_property_filename.c_str());
    return Error() << "Unable to parse persistent property file: Could not parse protobuf";
}

去读取persist属性的存储文件到file_contents中,然后做解析,返回成PersistentProperties。

system/core/init/persistent_properties.cpp

Result<std::string> ReadPersistentPropertyFile() {
		//std::string persistent_property_filename = "/data/property/persistent_properties";
    const std::string temp_filename = persistent_property_filename + ".tmp";
    if (access(temp_filename.c_str(), F_OK) == 0) {
        LOG(INFO)
            << "Found temporary property file while attempting to persistent system properties"
               " a previous persistent property write may have failed";
        unlink(temp_filename.c_str());
    }
    auto file_contents = ReadFile(persistent_property_filename);
    if (!file_contents.ok()) {
        return Error() << "Unable to read persistent property file: " << file_contents.error();
    }
    return *file_contents;
}

可见persistent_property_filename这个文件就是/data/property/persistent_properties,这里还做了个保护,如果之前有写失败的,就把tmp文件清空。

总结

属性服务是在Init的第二个初始化阶段去启动的,整体分了两个部分去做。第一部分主要是初始化属性空间,包括prop_area的内存区域初始化和系统默认属性的load工作;第二部分是属性服务的启动,创建了通信的socket,并注册了init和set两种事件的对应处理方法。另外在处理初始化的时候load了persist属性。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值