Create a host side checker for property info file correctness
Bug: 36001741 Test: verify a valid property info file and fail due to various failures Change-Id: Iadd38796aa619f87ec559fe5687bbe2009df8b2d
This commit is contained in:
parent
2af1be4c16
commit
919458c350
9 changed files with 164 additions and 51 deletions
|
@ -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<PropertyInfoEntry> 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<PropertyInfoEntry>* 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<std::string>{};
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
cc_library_static {
|
||||
name: "libpropertyinfoparser",
|
||||
host_supported: true,
|
||||
srcs: ["property_info_parser.cpp"],
|
||||
|
||||
cpp_std: "experimental",
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#define PROPERTY_INFO_PARSER_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
namespace android {
|
||||
namespace properties {
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -41,6 +41,10 @@ bool BuildTrie(const std::vector<PropertyInfoEntry>& 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<PropertyInfoEntry>* property_infos,
|
||||
std::vector<std::string>* errors);
|
||||
|
||||
} // namespace properties
|
||||
} // namespace android
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
#include <property_info_serializer/property_info_serializer.h>
|
||||
|
||||
#include <android-base/strings.h>
|
||||
|
||||
#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<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, &property_info_entry, &parse_error)) {
|
||||
errors->emplace_back(parse_error);
|
||||
continue;
|
||||
}
|
||||
|
||||
property_infos->emplace_back(property_info_entry);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace properties
|
||||
} // namespace android
|
|
@ -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
|
14
property_service/property_info_checker/Android.bp
Normal file
14
property_service/property_info_checker/Android.bp
Normal file
|
@ -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"],
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include <android-base/file.h>
|
||||
|
||||
#include <property_info_serializer/property_info_serializer.h>
|
||||
|
||||
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<PropertyInfoEntry>{};
|
||||
|
||||
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<std::string>{};
|
||||
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;
|
||||
}
|
Loading…
Reference in a new issue