概述:
代码路径: system/core/init/property_service.cpp
用处:
加载属性的se信息
代码
// 从文件中读取属性信息
/** 文件内容格式
ro.product.cpu.abi u:object_r:build_prop:s0 exact string
ro.product.cpu.abilist u:object_r:build_prop:s0 exact string
ro.product.cpu.abilist32 u:object_r:build_prop:s0 exact string
ro.product.cpu.abilist64 u:object_r:build_prop:s0 exact string
*/
void CreateSerializedPropertyInfo() {
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;
}
...
}
}
// 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;
};
LoadPropertyInfoFromFile
bool LoadPropertyInfoFromFile(const std::string& filename,
std::vector<PropertyInfoEntry>* property_infos) {
auto file_contents = std::string();
// 将文件内容读取到字符串中,
// 参考连接:https://blog.youkuaiyun.com/u014023550/article/details/129063608
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;
}
ParsePropertyInfoFile
将字符串分隔成一行一行的字符串,在将每一行的信息放入到PropertyInfoEntry 结构体中。
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);
}
}
ParsePropertyInfoLine
通过 SpaceTokenizer 挨个读取对应信息
bool ParsePropertyInfoLine(const std::string& line, bool require_prefix_or_exact,
PropertyInfoEntry* out, std::string* error) {
auto tokenizer = SpaceTokenizer(line);
auto property = tokenizer.GetNext();
if (property.empty()) {
*error = "Did not find a property entry in '" + line + "'";
return false;
}
auto context = tokenizer.GetNext();
if (context.empty()) {
*error = "Did not find a context entry in '" + line + "'";
return false;
}
// It is not an error to not find exact_match or a type, as older files will not contain them.
auto match_operation = tokenizer.GetNext();
// We reformat type to be space deliminated regardless of the input whitespace for easier storage
// and subsequent parsing.
auto type_strings = std::vector<std::string>{};
auto type = tokenizer.GetNext();
while (!type.empty()) {
type_strings.emplace_back(type);
type = tokenizer.GetNext();
}
bool exact_match = false;
if (match_operation == "exact") {
exact_match = true;
} else if (match_operation != "prefix" && match_operation != "" && require_prefix_or_exact) {
*error = "Match operation '" + match_operation +
"' is not valid: must be either 'prefix' or 'exact'";
return false;
}
if (!type_strings.empty() && !IsTypeValid(type_strings)) {
*error = "Type '" + Join(type_strings, " ") + "' is not valid";
return false;
}
*out = {property, context, Join(type_strings, " "), exact_match};
return true;
}
**SpaceTokenizer **
class SpaceTokenizer {
public:
SpaceTokenizer(const std::string& string)
: string_(string), it_(string_.begin()), end_(string_.end()) {}
// 获取字符串中的单词,然后跳过空白符
std::string GetNext() {
auto next = std::string();
// 获取单词
while (it_ != end_ && !isspace(*it_)) {
next.push_back(*it_++);
}
// 跳过空白符
while (it_ != end_ && isspace(*it_)) {
it_++;
}
return next;
}
std::string GetRemaining() { return std::string(it_, end_); }
private:
std::string string_;
std::string::const_iterator it_;
std::string::const_iterator end_;
};