文章目录
1 属性服务
属性服务的启动在init进程中,init进程初始化的第二阶段初始化中启动了属性服务。
system/core/init/init.cpp
int SecondStageMain(int argc, char** argv) {
...
PropertyInit();
...
StartPropertyService(&property_fd);
...
2 启动属性服务
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);
CreateSerializedPropertyInfo();
if (__system_property_area_init()) {
LOG(FATAL) << "Failed to initialize property area";
}
if (!property_info_area.LoadDefaultPath()) {
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();
ProcessKernelCmdline();
ProcessBootconfig();
// Propagate the kernel variables to internal variables
// used by init as well as the current required properties.
ExportKernelBootProps();
PropertyLoadBootDefaults();
}
接下来分析一下这个函数
mkdir("/dev/__properties__", S_IRWXU | S_IXGRP | S_IXOTH);
首先创建属性服务的存储目录,位于/dev/properties,权限为711,即rwx–x–x
2.1 写入序列化属性上下文信息
system/core/init/property_service.cpp
void CreateSerializedPropertyInfo() {
//创建一个vector用于存储selinux中属性相关
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", //这个函数的具体作用就是从文件中解析属性相关的,写到vector中
&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("/dev/selinux/apex_property_contexts", R_OK) != -1) {
LoadPropertyInfoFromFile("/dev/selinux/apex_property_contexts", &property_infos);
}
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 (access("/vendor/etc/selinux/vendor_property_contexts", R_OK) != -1) {
LoadPropertyInfoFromFile("/vendor/etc/selinux/vendor_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);
LoadPropertyInfoFromFile("/vendor_property_contexts", &property_infos);
LoadPropertyInfoFromFile("/product_property_contexts", &property_infos);
LoadPropertyInfoFromFile("/odm_property_contexts", &property_infos);
LoadPropertyInfoFromFile("/dev/selinux/apex_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;
}
//上面解析的数据都写到了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";
}
selinux_android_restorecon(kPropertyInfosPath, 0);
}
创建一个存储属性服务的vector——property_infos,存储的是PropertyInfoEntry,是一个结构体
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;
};
包含一些函数和一些字段。
if (!LoadPropertyInfoFromFile("/system/etc/selinux/plat_property_contexts", &property_infos)) {
return;
}
然后就是调用LoadPropertyInfoFromFile加载各个镜像中能够的属性上下文到property_infos这个结构体中。
bool LoadPropertyInfoFromFile(const std::string& filename,
std::vector<PropertyInfoEntry>* property_infos) {
auto file_contents = std::string();
if (!ReadFileToString(filename, &file_contents)) {
PLOG(ERROR) << "Could not read properties from '" << filename << "'";
return false;
}
auto errors = std::vector<std::string>{
};
bool require_prefix_or_exact = SelinuxGetVendorAndroidVersion() >= __ANDROID_API_R__;
ParsePropertyInfoFile(file_contents, require_prefix_or_exact, property_infos, &errors);
// Individual parsing errors are reported but do not cause a failed boot, which is what
// returning false would do here.
for (const auto& error : errors) {
LOG(ERROR) << "Could not read line from '" << filename << "': " << error;
}
return true;
}
读取文件中的属性上下文,并生成string字符串file_contents。require_prefix_or_exact用于判断属性是不是分离存放在各个镜像中,如果版本大于R,安卓11,则为true。
system/core/property_service/libpropertyinfoserializer/property_info_file.cpp
void ParsePropertyInfoFile(const std::string& file_contents, bool require_prefix_or_exact,
std::vector<PropertyInfoEntry>* property_infos,
std::vector<std::string>* errors) {
// Do not clear property_infos to allow this function to be called on multiple files, with
// their results concatenated.
errors->clear();
for (const auto& line : Split(file_contents, "\n")) {
auto trimmed_line = Trim(line);
if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) {
continue;
}
auto property_info_entry = PropertyInfoEntry{
};
auto parse_error = std::string{
};
if (!ParsePropertyInfoLine(trimmed_line, require_prefix_or_exact, &property_info_entry,
&parse_error)) {
errors->emplace_back(parse_error);
continue;
}
property_infos->emplace_back(property_info_entry);
}
}
然后解析文件中的属性,以行\n为分割,然后在ParsePropertyInfoLine中解析。
bool ParsePropertyInfoLine(const std::string& line, bool require_prefix_or_exact,
PropertyInfoEntry* out, std::string* error)<