前言
在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属性。