diff --git a/init/property_service.cpp b/init/property_service.cpp index 439ab3994..7aa94b09b 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -58,7 +58,6 @@ #include "init.h" #include "persistent_properties.h" -#include "space_tokenizer.h" #include "util.h" using android::base::ReadFileToString; @@ -69,6 +68,7 @@ using android::base::Timer; using android::base::Trim; using android::base::WriteStringToFile; using android::properties::BuildTrie; +using android::properties::ParsePropertyInfoFile; using android::properties::PropertyInfoAreaFile; using android::properties::PropertyInfoEntry; @@ -728,22 +728,6 @@ static int SelinuxAuditCallback(void* data, security_class_t /*cls*/, char* buf, return 0; } -Result ParsePropertyInfoLine(const std::string& line) { - auto tokenizer = SpaceTokenizer(line); - - auto property = tokenizer.GetNext(); - if (property.empty()) return Error() << "Did not find a property entry in '" << line << "'"; - - auto context = tokenizer.GetNext(); - if (context.empty()) return Error() << "Did not find a context entry in '" << line << "'"; - - // It is not an error to not find these, as older files will not contain them. - auto exact_match = tokenizer.GetNext(); - auto schema = tokenizer.GetRemaining(); - - return {property, context, schema, exact_match == "exact"}; -} - bool LoadPropertyInfoFromFile(const std::string& filename, std::vector* property_infos) { auto file_contents = std::string(); @@ -752,20 +736,14 @@ bool LoadPropertyInfoFromFile(const std::string& filename, return false; } - for (const auto& line : Split(file_contents, "\n")) { - auto trimmed_line = Trim(line); - if (trimmed_line.empty() || StartsWith(trimmed_line, "#")) { - continue; - } - - auto property_info = ParsePropertyInfoLine(line); - if (!property_info) { - LOG(ERROR) << "Could not read line from '" << filename << "': " << property_info.error(); - continue; - } - - property_infos->emplace_back(*property_info); + auto errors = std::vector{}; + ParsePropertyInfoFile(file_contents, 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; } diff --git a/property_service/libpropertyinfoparser/Android.bp b/property_service/libpropertyinfoparser/Android.bp index 3e732b51c..c046417dc 100644 --- a/property_service/libpropertyinfoparser/Android.bp +++ b/property_service/libpropertyinfoparser/Android.bp @@ -1,5 +1,6 @@ cc_library_static { name: "libpropertyinfoparser", + host_supported: true, srcs: ["property_info_parser.cpp"], cpp_std: "experimental", diff --git a/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h b/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h index 8c3507e4f..2ee816124 100644 --- a/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h +++ b/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h @@ -18,6 +18,7 @@ #define PROPERTY_INFO_PARSER_H #include +#include namespace android { namespace properties { diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp index 20e5e1366..bc28e8276 100644 --- a/property_service/libpropertyinfoserializer/Android.bp +++ b/property_service/libpropertyinfoserializer/Android.bp @@ -1,5 +1,6 @@ cc_defaults { name: "propertyinfoserializer_defaults", + host_supported: true, cpp_std: "experimental", sanitize: { misc_undefined: ["signed-integer-overflow"], @@ -19,6 +20,7 @@ cc_library_static { name: "libpropertyinfoserializer", defaults: ["propertyinfoserializer_defaults"], srcs: [ + "property_info_file.cpp", "property_info_serializer.cpp", "trie_builder.cpp", "trie_serializer.cpp", diff --git a/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h b/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h index f7e708ede..d2ec385d4 100644 --- a/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h +++ b/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h @@ -41,6 +41,10 @@ bool BuildTrie(const std::vector& property_info, const std::string& default_context, const std::string& default_schema, std::string* serialized_trie, std::string* error); +void ParsePropertyInfoFile(const std::string& file_contents, + std::vector* property_infos, + std::vector* errors); + } // namespace properties } // namespace android diff --git a/property_service/libpropertyinfoserializer/property_info_file.cpp b/property_service/libpropertyinfoserializer/property_info_file.cpp new file mode 100644 index 000000000..702f219d8 --- /dev/null +++ b/property_service/libpropertyinfoserializer/property_info_file.cpp @@ -0,0 +1,62 @@ +#include + +#include + +#include "space_tokenizer.h" + +using android::base::Split; +using android::base::StartsWith; +using android::base::Trim; + +namespace android { +namespace properties { + +bool ParsePropertyInfoLine(const std::string& line, 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 these, as older files will not contain them. + auto exact_match = tokenizer.GetNext(); + auto schema = tokenizer.GetRemaining(); + + *out = {property, context, schema, exact_match == "exact"}; + return true; +} + +void ParsePropertyInfoFile(const std::string& file_contents, + std::vector* property_infos, + std::vector* 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, &property_info_entry, &parse_error)) { + errors->emplace_back(parse_error); + continue; + } + + property_infos->emplace_back(property_info_entry); + } +} + +} // namespace properties +} // namespace android diff --git a/init/space_tokenizer.h b/property_service/libpropertyinfoserializer/space_tokenizer.h similarity index 51% rename from init/space_tokenizer.h rename to property_service/libpropertyinfoserializer/space_tokenizer.h index e7e22c551..fba0c5841 100644 --- a/init/space_tokenizer.h +++ b/property_service/libpropertyinfoserializer/space_tokenizer.h @@ -14,37 +14,37 @@ * limitations under the License. */ -#ifndef _INIT_SPACE_TOKENIZER_H -#define _INIT_SPACE_TOKENIZER_H +#ifndef PROPERTY_INFO_SERIALIZER_SPACE_TOKENIZER_H +#define PROPERTY_INFO_SERIALIZER_SPACE_TOKENIZER_H namespace android { -namespace init { +namespace properties { class SpaceTokenizer { - public: - SpaceTokenizer(const std::string& string) - : string_(string), it_(string_.begin()), end_(string_.end()) {} + 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 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_); } + std::string GetRemaining() { return std::string(it_, end_); } - private: - std::string string_; - std::string::const_iterator it_; - std::string::const_iterator end_; + private: + std::string string_; + std::string::const_iterator it_; + std::string::const_iterator end_; }; -} // namespace init +} // namespace properties } // namespace android #endif diff --git a/property_service/property_info_checker/Android.bp b/property_service/property_info_checker/Android.bp new file mode 100644 index 000000000..2c9a2ba2a --- /dev/null +++ b/property_service/property_info_checker/Android.bp @@ -0,0 +1,14 @@ +cc_binary { + name: "property_info_checker", + host_supported: true, + cpp_std: "experimental", + sanitize: { + misc_undefined: ["signed-integer-overflow"], + }, + static_libs: [ + "libpropertyinfoserializer", + "libpropertyinfoparser", + "libbase", + ], + srcs: ["property_info_checker.cpp"], +} \ No newline at end of file diff --git a/property_service/property_info_checker/property_info_checker.cpp b/property_service/property_info_checker/property_info_checker.cpp new file mode 100644 index 000000000..e4f8264d4 --- /dev/null +++ b/property_service/property_info_checker/property_info_checker.cpp @@ -0,0 +1,51 @@ +#include +#include +#include + +#include + +#include + +using android::base::ReadFileToString; +using android::properties::BuildTrie; +using android::properties::ParsePropertyInfoFile; +using android::properties::PropertyInfoEntry; + +int main(int argc, char** argv) { + if (argc < 2) { + std::cerr << "A list of property info files to be checked is expected on the command line" + << std::endl; + return -1; + } + + auto property_info_entries = std::vector{}; + + for (int i = 1; i < argc; ++i) { + auto filename = argv[i]; + auto file_contents = std::string{}; + if (!ReadFileToString(filename, &file_contents)) { + std::cerr << "Could not read properties from '" << filename << "'" << std::endl; + return -1; + } + + auto errors = std::vector{}; + ParsePropertyInfoFile(file_contents, &property_info_entries, &errors); + if (!errors.empty()) { + for (const auto& error : errors) { + std::cerr << "Could not read line from '" << filename << "': " << error << std::endl; + } + return -1; + } + } + + auto serialized_contexts = std::string{}; + auto build_trie_error = std::string{}; + + if (!BuildTrie(property_info_entries, "u:object_r:default_prop:s0", "\\s*", &serialized_contexts, + &build_trie_error)) { + std::cerr << "Unable to serialize property contexts: " << build_trie_error << std::endl; + return -1; + } + + return 0; +}