summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Cherry2017-10-27 17:18:02 -0500
committerTom Cherry2017-12-11 18:11:42 -0600
commitd853f77ed3a70bc0d80edcba775990348c6d3c76 (patch)
treeedb9595e39616597ec4c5255b24539d97b727f3e
parentd7edcc9bc4728c63f04a1a85556c9714c2911b3c (diff)
downloadplatform-system-core-d853f77ed3a70bc0d80edcba775990348c6d3c76.tar.gz
platform-system-core-d853f77ed3a70bc0d80edcba775990348c6d3c76.tar.xz
platform-system-core-d853f77ed3a70bc0d80edcba775990348c6d3c76.zip
Parse property contexts via a serialized trie
Currently, whenever a new program starts, libc initializes two data structures related to properties from the raw property_context files. There are two problems here, 1) This takes roughly 1.2ms on a trivial program to generate contents that could otherwise be cached. 2) One of the data structures is a descending list of prefixes, each of which needs to be checked, whereas a trie would be more efficient. This change introduces two libraries, 1) libpropertycontextserializer meant to be used by property_service to create a serialized trie containing all of the property contexts. 2) libpropertycontextparser meant to be used by libc's property functions to parse this serialized trie during property lookup. This new trie also contains the ability to have exact matches instead of prefix matches for properties, which was not possible before. Bug: 36001741 Change-Id: I42324f04c4d995a0e055e9685d79f40393dfca51
l---------property_service/.clang-format1
-rw-r--r--property_service/Android.bp1
-rw-r--r--property_service/libpropertyinfoparser/Android.bp16
-rw-r--r--property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h221
-rw-r--r--property_service/libpropertyinfoparser/property_info_parser.cpp220
-rw-r--r--property_service/libpropertyinfoserializer/Android.bp38
-rw-r--r--property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h47
-rw-r--r--property_service/libpropertyinfoserializer/property_info_serializer.cpp47
-rw-r--r--property_service/libpropertyinfoserializer/property_info_serializer_test.cpp750
-rw-r--r--property_service/libpropertyinfoserializer/trie_builder.cpp105
-rw-r--r--property_service/libpropertyinfoserializer/trie_builder.h124
-rw-r--r--property_service/libpropertyinfoserializer/trie_builder_test.cpp129
-rw-r--r--property_service/libpropertyinfoserializer/trie_node_arena.h108
-rw-r--r--property_service/libpropertyinfoserializer/trie_serializer.cpp142
-rw-r--r--property_service/libpropertyinfoserializer/trie_serializer.h55
15 files changed, 2004 insertions, 0 deletions
diff --git a/property_service/.clang-format b/property_service/.clang-format
new file mode 120000
index 000000000..fd0645fdf
--- /dev/null
+++ b/property_service/.clang-format
@@ -0,0 +1 @@
../.clang-format-2 \ No newline at end of file
diff --git a/property_service/Android.bp b/property_service/Android.bp
new file mode 100644
index 000000000..b44c29601
--- /dev/null
+++ b/property_service/Android.bp
@@ -0,0 +1 @@
subdirs = ["*"]
diff --git a/property_service/libpropertyinfoparser/Android.bp b/property_service/libpropertyinfoparser/Android.bp
new file mode 100644
index 000000000..3e732b51c
--- /dev/null
+++ b/property_service/libpropertyinfoparser/Android.bp
@@ -0,0 +1,16 @@
1cc_library_static {
2 name: "libpropertyinfoparser",
3 srcs: ["property_info_parser.cpp"],
4
5 cpp_std: "experimental",
6 sanitize: {
7 misc_undefined: ["signed-integer-overflow"],
8 },
9 cppflags: [
10 "-Wall",
11 "-Wextra",
12 "-Werror",
13 ],
14 stl: "none",
15 export_include_dirs: ["include"],
16}
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
new file mode 100644
index 000000000..c2114ccff
--- /dev/null
+++ b/property_service/libpropertyinfoparser/include/property_info_parser/property_info_parser.h
@@ -0,0 +1,221 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#ifndef PROPERTY_INFO_PARSER_H
18#define PROPERTY_INFO_PARSER_H
19
20#include <stdint.h>
21
22namespace android {
23namespace properties {
24
25// The below structs intentionally do not end with char name[0] or other tricks to allocate
26// with a dynamic size, such that they can be added onto in the future without breaking
27// backwards compatibility.
28struct PropertyEntry {
29 uint32_t name_offset;
30 uint32_t namelen;
31
32 // This is the context match for this node_; ~0u if it doesn't correspond to any.
33 uint32_t context_index;
34 // This is the schema for this node_; ~0u if it doesn't correspond to any.
35 uint32_t schema_index;
36};
37
38struct TrieNodeInternal {
39 // This points to a property entry struct, which includes the name for this node
40 uint32_t property_entry;
41
42 // Children are a sorted list of child nodes_; binary search them.
43 uint32_t num_child_nodes;
44 uint32_t child_nodes;
45
46 // Prefixes are terminating prefix matches at this node, sorted longest to smallest
47 // Take the first match sequentially found with StartsWith().
48 uint32_t num_prefixes;
49 uint32_t prefix_entries;
50
51 // Exact matches are a sorted list of exact matches at this node_; binary search them.
52 uint32_t num_exact_matches;
53 uint32_t exact_match_entries;
54};
55
56struct PropertyInfoAreaHeader {
57 // The current version of this data as created by property service.
58 uint32_t current_version;
59 // The lowest version of libc that can properly parse this data.
60 uint32_t minimum_supported_version;
61 uint32_t size;
62 uint32_t contexts_offset;
63 uint32_t schemas_offset;
64 uint32_t root_offset;
65};
66
67class SerializedData {
68 public:
69 uint32_t size() const {
70 return reinterpret_cast<const PropertyInfoAreaHeader*>(data_base_)->size;
71 }
72
73 const char* c_string(uint32_t offset) const {
74 if (offset != 0 && offset > size()) return nullptr;
75 return static_cast<const char*>(data_base_ + offset);
76 }
77
78 const uint32_t* uint32_array(uint32_t offset) const {
79 if (offset != 0 && offset > size()) return nullptr;
80 return reinterpret_cast<const uint32_t*>(data_base_ + offset);
81 }
82
83 uint32_t uint32(uint32_t offset) const {
84 if (offset != 0 && offset > size()) return ~0u;
85 return *reinterpret_cast<const uint32_t*>(data_base_ + offset);
86 }
87
88 const char* data_base() const { return data_base_; }
89
90 private:
91 const char data_base_[0];
92};
93
94class TrieNode {
95 public:
96 TrieNode() : serialized_data_(nullptr), trie_node_base_(nullptr) {}
97 TrieNode(const SerializedData* data_base, const TrieNodeInternal* trie_node_base)
98 : serialized_data_(data_base), trie_node_base_(trie_node_base) {}
99
100 const char* name() const {
101 return serialized_data_->c_string(node_property_entry()->name_offset);
102 }
103
104 uint32_t context_index() const { return node_property_entry()->context_index; }
105 uint32_t schema_index() const { return node_property_entry()->schema_index; }
106
107 uint32_t num_child_nodes() const { return trie_node_base_->num_child_nodes; }
108 TrieNode child_node(int n) const {
109 uint32_t child_node_offset = serialized_data_->uint32_array(trie_node_base_->child_nodes)[n];
110 const TrieNodeInternal* trie_node_base =
111 reinterpret_cast<const TrieNodeInternal*>(serialized_data_->data_base() + child_node_offset);
112 return TrieNode(serialized_data_, trie_node_base);
113 }
114
115 bool FindChildForString(const char* input, uint32_t namelen, TrieNode* child) const;
116
117 uint32_t num_prefixes() const { return trie_node_base_->num_prefixes; }
118 const PropertyEntry* prefix(int n) const {
119 uint32_t prefix_entry_offset =
120 serialized_data_->uint32_array(trie_node_base_->prefix_entries)[n];
121 return reinterpret_cast<const PropertyEntry*>(serialized_data_->data_base() +
122 prefix_entry_offset);
123 }
124
125 uint32_t num_exact_matches() const { return trie_node_base_->num_exact_matches; }
126 const PropertyEntry* exact_match(int n) const {
127 uint32_t exact_match_entry_offset =
128 serialized_data_->uint32_array(trie_node_base_->exact_match_entries)[n];
129 return reinterpret_cast<const PropertyEntry*>(serialized_data_->data_base() +
130 exact_match_entry_offset);
131 }
132
133 private:
134 const PropertyEntry* node_property_entry() const {
135 return reinterpret_cast<const PropertyEntry*>(serialized_data_->data_base() +
136 trie_node_base_->property_entry);
137 }
138
139 const SerializedData* serialized_data_;
140 const TrieNodeInternal* trie_node_base_;
141};
142
143class PropertyInfoArea : private SerializedData {
144 public:
145 void GetPropertyInfoIndexes(const char* name, uint32_t* context_index,
146 uint32_t* schema_index) const;
147 void GetPropertyInfo(const char* property, const char** context, const char** schema) const;
148
149 int FindContextIndex(const char* context) const;
150 int FindSchemaIndex(const char* schema) const;
151
152 const char* context(uint32_t index) const {
153 uint32_t context_array_size_offset = contexts_offset();
154 const uint32_t* context_array = uint32_array(context_array_size_offset + sizeof(uint32_t));
155 return data_base() + context_array[index];
156 }
157
158 const char* schema(uint32_t index) const {
159 uint32_t schema_array_size_offset = schemas_offset();
160 const uint32_t* schema_array = uint32_array(schema_array_size_offset + sizeof(uint32_t));
161 return data_base() + schema_array[index];
162 }
163
164 uint32_t current_version() const { return header()->current_version; }
165 uint32_t minimum_supported_version() const { return header()->minimum_supported_version; }
166
167 uint32_t size() const { return SerializedData::size(); }
168
169 uint32_t num_contexts() const { return uint32_array(contexts_offset())[0]; }
170 uint32_t num_schemas() const { return uint32_array(schemas_offset())[0]; }
171
172 TrieNode root_node() const { return trie(header()->root_offset); }
173
174 private:
175 const PropertyInfoAreaHeader* header() const {
176 return reinterpret_cast<const PropertyInfoAreaHeader*>(data_base());
177 }
178 uint32_t contexts_offset() const { return header()->contexts_offset; }
179 uint32_t contexts_array_offset() const { return contexts_offset() + sizeof(uint32_t); }
180 uint32_t schemas_offset() const { return header()->schemas_offset; }
181 uint32_t schemas_array_offset() const { return schemas_offset() + sizeof(uint32_t); }
182
183 TrieNode trie(uint32_t offset) const {
184 if (offset != 0 && offset > size()) return TrieNode();
185 const TrieNodeInternal* trie_node_base =
186 reinterpret_cast<const TrieNodeInternal*>(data_base() + offset);
187 return TrieNode(this, trie_node_base);
188 }
189};
190
191// This is essentially a smart pointer for read only mmap region for property contexts.
192class PropertyInfoAreaFile {
193 public:
194 PropertyInfoAreaFile() : mmap_base_(nullptr), mmap_size_(0) {}
195 ~PropertyInfoAreaFile() { Reset(); }
196
197 PropertyInfoAreaFile(const PropertyInfoAreaFile&) = delete;
198 void operator=(const PropertyInfoAreaFile&) = delete;
199 PropertyInfoAreaFile(PropertyInfoAreaFile&&) = default;
200 PropertyInfoAreaFile& operator=(PropertyInfoAreaFile&&) = default;
201
202 bool LoadDefaultPath();
203 bool LoadPath(const char* filename);
204
205 const PropertyInfoArea* operator->() const {
206 return reinterpret_cast<const PropertyInfoArea*>(mmap_base_);
207 }
208
209 explicit operator bool() const { return mmap_base_ != nullptr; }
210
211 void Reset();
212
213 private:
214 void* mmap_base_;
215 size_t mmap_size_;
216};
217
218} // namespace properties
219} // namespace android
220
221#endif
diff --git a/property_service/libpropertyinfoparser/property_info_parser.cpp b/property_service/libpropertyinfoparser/property_info_parser.cpp
new file mode 100644
index 000000000..84f8c29f8
--- /dev/null
+++ b/property_service/libpropertyinfoparser/property_info_parser.cpp
@@ -0,0 +1,220 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "property_info_parser/property_info_parser.h"
18
19#include <fcntl.h>
20#include <string.h>
21#include <sys/mman.h>
22#include <sys/stat.h>
23#include <sys/types.h>
24
25namespace android {
26namespace properties {
27
28namespace {
29
30// Binary search to find index of element in an array compared via f(search).
31template <typename F>
32int Find(uint32_t array_length, F&& f) {
33 int bottom = 0;
34 int top = array_length - 1;
35 while (top >= bottom) {
36 int search = (top + bottom) / 2;
37
38 auto cmp = f(search);
39
40 if (cmp == 0) return search;
41 if (cmp < 0) bottom = search + 1;
42 if (cmp > 0) top = search - 1;
43 }
44 return -1;
45}
46
47} // namespace
48
49// Binary search the list of contexts to find the index of a given context string.
50// Only should be used for TrieSerializer to construct the Trie.
51int PropertyInfoArea::FindContextIndex(const char* context) const {
52 return Find(num_contexts(), [this, context](auto array_offset) {
53 auto string_offset = uint32_array(contexts_array_offset())[array_offset];
54 return strcmp(c_string(string_offset), context);
55 });
56}
57
58// Binary search the list of schemas to find the index of a given schema string.
59// Only should be used for TrieSerializer to construct the Trie.
60int PropertyInfoArea::FindSchemaIndex(const char* schema) const {
61 return Find(num_schemas(), [this, schema](auto array_offset) {
62 auto string_offset = uint32_array(schemas_array_offset())[array_offset];
63 return strcmp(c_string(string_offset), schema);
64 });
65}
66
67// Binary search the list of children nodes to find a TrieNode for a given property piece.
68// Used to traverse the Trie in GetPropertyInfoIndexes().
69bool TrieNode::FindChildForString(const char* name, uint32_t namelen, TrieNode* child) const {
70 auto node_index = Find(trie_node_base_->num_child_nodes, [this, name, namelen](auto array_offset) {
71 const char* child_name = child_node(array_offset).name();
72 int cmp = strncmp(child_name, name, namelen);
73 if (cmp == 0 && child_name[namelen] != '\0') {
74 // We use strncmp() since name isn't null terminated, but we don't want to match only a
75 // prefix of a child node's name, so we check here if we did only match a prefix and
76 // return 1, to indicate to the binary search to search earlier in the array for the real
77 // match.
78 return 1;
79 }
80 return cmp;
81 });
82
83 if (node_index == -1) {
84 return false;
85 }
86 *child = child_node(node_index);
87 return true;
88}
89
90void PropertyInfoArea::GetPropertyInfoIndexes(const char* name, uint32_t* context_index,
91 uint32_t* schema_index) const {
92 uint32_t return_context_index = ~0u;
93 uint32_t return_schema_index = ~0u;
94 const char* remaining_name = name;
95 auto trie_node = root_node();
96 while (true) {
97 const char* sep = strchr(remaining_name, '.');
98
99 // Apply prefix match for prefix deliminated with '.'
100 if (trie_node.context_index() != ~0u) {
101 return_context_index = trie_node.context_index();
102 }
103 if (trie_node.schema_index() != ~0u) {
104 return_schema_index = trie_node.schema_index();
105 }
106
107 if (sep == nullptr) {
108 break;
109 }
110
111 const uint32_t substr_size = sep - remaining_name;
112 TrieNode child_node;
113 if (!trie_node.FindChildForString(remaining_name, substr_size, &child_node)) {
114 break;
115 }
116
117 trie_node = child_node;
118 remaining_name = sep + 1;
119 }
120
121 // We've made it to a leaf node, so check contents and return appropriately.
122 // Check exact matches
123 for (uint32_t i = 0; i < trie_node.num_exact_matches(); ++i) {
124 if (!strcmp(c_string(trie_node.exact_match(i)->name_offset), remaining_name)) {
125 if (context_index != nullptr) *context_index = trie_node.exact_match(i)->context_index;
126 if (schema_index != nullptr) *schema_index = trie_node.exact_match(i)->schema_index;
127 return;
128 }
129 }
130 // Check prefix matches for prefixes not deliminated with '.'
131 const uint32_t remaining_name_size = strlen(remaining_name);
132 for (uint32_t i = 0; i < trie_node.num_prefixes(); ++i) {
133 auto prefix_len = trie_node.prefix(i)->namelen;
134 if (prefix_len > remaining_name_size) continue;
135
136 if (!strncmp(c_string(trie_node.prefix(i)->name_offset), remaining_name, prefix_len)) {
137 if (context_index != nullptr) *context_index = trie_node.prefix(i)->context_index;
138 if (schema_index != nullptr) *schema_index = trie_node.prefix(i)->schema_index;
139 return;
140 }
141 }
142 // Return previously found '.' deliminated prefix match.
143 if (context_index != nullptr) *context_index = return_context_index;
144 if (schema_index != nullptr) *schema_index = return_schema_index;
145 return;
146}
147
148void PropertyInfoArea::GetPropertyInfo(const char* property, const char** context,
149 const char** schema) const {
150 uint32_t context_index;
151 uint32_t schema_index;
152 GetPropertyInfoIndexes(property, &context_index, &schema_index);
153 if (context != nullptr) {
154 if (context_index == ~0u) {
155 *context = nullptr;
156 } else {
157 *context = this->context(context_index);
158 }
159 }
160 if (schema != nullptr) {
161 if (schema_index == ~0u) {
162 *schema = nullptr;
163 } else {
164 *schema = this->schema(schema_index);
165 }
166 }
167}
168
169bool PropertyInfoAreaFile::LoadDefaultPath() {
170 return LoadPath("/dev/__properties__/property_info");
171}
172
173bool PropertyInfoAreaFile::LoadPath(const char* filename) {
174 int fd = open(filename, O_CLOEXEC | O_NOFOLLOW | O_RDONLY);
175
176 struct stat fd_stat;
177 if (fstat(fd, &fd_stat) < 0) {
178 close(fd);
179 return false;
180 }
181
182 if ((fd_stat.st_uid != 0) || (fd_stat.st_gid != 0) ||
183 ((fd_stat.st_mode & (S_IWGRP | S_IWOTH)) != 0) ||
184 (fd_stat.st_size < static_cast<off_t>(sizeof(PropertyInfoArea)))) {
185 close(fd);
186 return false;
187 }
188
189 auto mmap_size = fd_stat.st_size;
190
191 void* map_result = mmap(nullptr, mmap_size, PROT_READ, MAP_SHARED, fd, 0);
192 if (map_result == MAP_FAILED) {
193 close(fd);
194 return false;
195 }
196
197 auto property_info_area = reinterpret_cast<PropertyInfoArea*>(map_result);
198 if (property_info_area->minimum_supported_version() > 1 ||
199 property_info_area->size() != mmap_size) {
200 munmap(map_result, mmap_size);
201 close(fd);
202 return false;
203 }
204
205 close(fd);
206 mmap_base_ = map_result;
207 mmap_size_ = mmap_size;
208 return true;
209}
210
211void PropertyInfoAreaFile::Reset() {
212 if (mmap_size_ > 0) {
213 munmap(mmap_base_, mmap_size_);
214 }
215 mmap_base_ = nullptr;
216 mmap_size_ = 0;
217}
218
219} // namespace properties
220} // namespace android
diff --git a/property_service/libpropertyinfoserializer/Android.bp b/property_service/libpropertyinfoserializer/Android.bp
new file mode 100644
index 000000000..20e5e1366
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/Android.bp
@@ -0,0 +1,38 @@
1cc_defaults {
2 name: "propertyinfoserializer_defaults",
3 cpp_std: "experimental",
4 sanitize: {
5 misc_undefined: ["signed-integer-overflow"],
6 },
7 cppflags: [
8 "-Wall",
9 "-Wextra",
10 "-Werror",
11 ],
12 static_libs: [
13 "libpropertyinfoparser",
14 "libbase",
15 ],
16}
17
18cc_library_static {
19 name: "libpropertyinfoserializer",
20 defaults: ["propertyinfoserializer_defaults"],
21 srcs: [
22 "property_info_serializer.cpp",
23 "trie_builder.cpp",
24 "trie_serializer.cpp",
25 ],
26
27 export_include_dirs: ["include"],
28}
29
30cc_test {
31 name: "propertyinfoserializer_tests",
32 defaults: ["propertyinfoserializer_defaults"],
33 srcs: [
34 "trie_builder_test.cpp",
35 "property_info_serializer_test.cpp",
36 ],
37 static_libs: ["libpropertyinfoserializer"],
38}
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
new file mode 100644
index 000000000..f7e708ede
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/include/property_info_serializer/property_info_serializer.h
@@ -0,0 +1,47 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#ifndef PROPERTY_INFO_SERIALIZER_H
18#define PROPERTY_INFO_SERIALIZER_H
19
20#include <string>
21#include <vector>
22
23namespace android {
24namespace properties {
25
26struct PropertyInfoEntry {
27 PropertyInfoEntry() {}
28 template <typename T, typename U, typename V>
29 PropertyInfoEntry(T&& name, U&& context, V&& schema, bool exact_match)
30 : name(std::forward<T>(name)),
31 context(std::forward<U>(context)),
32 schema(std::forward<V>(schema)),
33 exact_match(exact_match) {}
34 std::string name;
35 std::string context;
36 std::string schema;
37 bool exact_match;
38};
39
40bool BuildTrie(const std::vector<PropertyInfoEntry>& property_info,
41 const std::string& default_context, const std::string& default_schema,
42 std::string* serialized_trie, std::string* error);
43
44} // namespace properties
45} // namespace android
46
47#endif
diff --git a/property_service/libpropertyinfoserializer/property_info_serializer.cpp b/property_service/libpropertyinfoserializer/property_info_serializer.cpp
new file mode 100644
index 000000000..656c96e33
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/property_info_serializer.cpp
@@ -0,0 +1,47 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "property_info_serializer/property_info_serializer.h"
18
19#include "property_info_parser/property_info_parser.h"
20
21#include <set>
22
23#include "trie_builder.h"
24#include "trie_serializer.h"
25
26namespace android {
27namespace properties {
28
29bool BuildTrie(const std::vector<PropertyInfoEntry>& property_info,
30 const std::string& default_context, const std::string& default_schema,
31 std::string* serialized_trie, std::string* error) {
32 // Check that names are legal first
33 auto trie_builder = TrieBuilder(default_context, default_schema);
34
35 for (const auto& [name, context, schema, is_exact] : property_info) {
36 if (!trie_builder.AddToTrie(name, context, schema, is_exact, error)) {
37 return false;
38 }
39 }
40
41 auto trie_serializer = TrieSerializer();
42 *serialized_trie = trie_serializer.SerializeTrie(trie_builder);
43 return true;
44}
45
46} // namespace properties
47} // namespace android
diff --git a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
new file mode 100644
index 000000000..b7a103e14
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp
@@ -0,0 +1,750 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "property_info_serializer/property_info_serializer.h"
18
19#include "property_info_parser/property_info_parser.h"
20
21#include <gtest/gtest.h>
22
23namespace android {
24namespace properties {
25
26TEST(propertyinfoserializer, TrieNodeCheck) {
27 auto property_info = std::vector<PropertyInfoEntry>{
28 {"test.", "1st", "1st", false}, {"test.test", "2nd", "2nd", false},
29
30 {"test.test1", "3rd", "3rd", true}, {"test.test2", "3rd", "3rd", true},
31 {"test.test3", "3rd", "3rd", true}, {"this.is.a.long.string", "4th", "4th", true},
32 };
33
34 auto serialized_trie = std::string();
35 auto build_trie_error = std::string();
36 ASSERT_TRUE(BuildTrie(property_info, "default", "default", &serialized_trie, &build_trie_error))
37 << build_trie_error;
38
39 auto property_info_area = reinterpret_cast<const PropertyInfoArea*>(serialized_trie.data());
40
41 // Initial checks for property area.
42 EXPECT_EQ(1U, property_info_area->current_version());
43 EXPECT_EQ(1U, property_info_area->minimum_supported_version());
44
45 // Check the root node
46 auto root_node = property_info_area->root_node();
47 EXPECT_STREQ("root", root_node.name());
48 EXPECT_STREQ("default", property_info_area->context(root_node.context_index()));
49 EXPECT_STREQ("default", property_info_area->schema(root_node.schema_index()));
50
51 EXPECT_EQ(0U, root_node.num_prefixes());
52 EXPECT_EQ(0U, root_node.num_exact_matches());
53
54 ASSERT_EQ(2U, root_node.num_child_nodes());
55
56 // Check the 'test'. node
57 TrieNode test_node;
58 ASSERT_TRUE(root_node.FindChildForString("test", 4, &test_node));
59
60 EXPECT_STREQ("test", test_node.name());
61 EXPECT_STREQ("1st", property_info_area->context(test_node.context_index()));
62 EXPECT_STREQ("1st", property_info_area->schema(test_node.schema_index()));
63
64 EXPECT_EQ(0U, test_node.num_child_nodes());
65
66 EXPECT_EQ(1U, test_node.num_prefixes());
67 {
68 auto prefix = test_node.prefix(0);
69 EXPECT_STREQ("test", serialized_trie.data() + prefix->name_offset);
70 EXPECT_EQ(4U, prefix->namelen);
71 EXPECT_STREQ("2nd", property_info_area->context(prefix->context_index));
72 EXPECT_STREQ("2nd", property_info_area->schema(prefix->schema_index));
73 }
74
75 EXPECT_EQ(3U, test_node.num_exact_matches());
76 {
77 auto match1 = test_node.exact_match(0);
78 auto match2 = test_node.exact_match(1);
79 auto match3 = test_node.exact_match(2);
80 EXPECT_STREQ("test1", serialized_trie.data() + match1->name_offset);
81 EXPECT_STREQ("test2", serialized_trie.data() + match2->name_offset);
82 EXPECT_STREQ("test3", serialized_trie.data() + match3->name_offset);
83
84 EXPECT_STREQ("3rd", property_info_area->context(match1->context_index));
85 EXPECT_STREQ("3rd", property_info_area->context(match2->context_index));
86 EXPECT_STREQ("3rd", property_info_area->context(match3->context_index));
87
88 EXPECT_STREQ("3rd", property_info_area->schema(match1->schema_index));
89 EXPECT_STREQ("3rd", property_info_area->schema(match2->schema_index));
90 EXPECT_STREQ("3rd", property_info_area->schema(match3->schema_index));
91 }
92
93 // Check the long string node
94 auto expect_empty_one_child = [](auto& node) {
95 EXPECT_EQ(-1U, node.context_index());
96 EXPECT_EQ(0U, node.num_prefixes());
97 EXPECT_EQ(0U, node.num_exact_matches());
98 EXPECT_EQ(1U, node.num_child_nodes());
99 };
100
101 // Start with 'this'
102 TrieNode long_string_node;
103 ASSERT_TRUE(root_node.FindChildForString("this", 4, &long_string_node));
104 expect_empty_one_child(long_string_node);
105
106 // Move to 'is'
107 ASSERT_TRUE(long_string_node.FindChildForString("is", 2, &long_string_node));
108 expect_empty_one_child(long_string_node);
109
110 // Move to 'a'
111 ASSERT_TRUE(long_string_node.FindChildForString("a", 1, &long_string_node));
112 expect_empty_one_child(long_string_node);
113
114 // Move to 'long'
115 ASSERT_TRUE(long_string_node.FindChildForString("long", 4, &long_string_node));
116 EXPECT_EQ(0U, long_string_node.num_prefixes());
117 EXPECT_EQ(1U, long_string_node.num_exact_matches());
118 EXPECT_EQ(0U, long_string_node.num_child_nodes());
119
120 auto final_match = long_string_node.exact_match(0);
121 EXPECT_STREQ("string", serialized_trie.data() + final_match->name_offset);
122 EXPECT_STREQ("4th", property_info_area->context(final_match->context_index));
123 EXPECT_STREQ("4th", property_info_area->schema(final_match->schema_index));
124}
125
126TEST(propertyinfoserializer, GetPropertyInfo) {
127 auto property_info = std::vector<PropertyInfoEntry>{
128 {"test.", "1st", "1st", false}, {"test.test", "2nd", "2nd", false},
129 {"test.test2.", "6th", "6th", false}, {"test.test", "5th", "5th", true},
130 {"test.test1", "3rd", "3rd", true}, {"test.test2", "7th", "7th", true},
131 {"test.test3", "3rd", "3rd", true}, {"this.is.a.long.string", "4th", "4th", true},
132 };
133
134 auto serialized_trie = std::string();
135 auto build_trie_error = std::string();
136 ASSERT_TRUE(BuildTrie(property_info, "default", "default", &serialized_trie, &build_trie_error))
137 << build_trie_error;
138
139 auto property_info_area = reinterpret_cast<const PropertyInfoArea*>(serialized_trie.data());
140
141 // Sanity check
142 auto root_node = property_info_area->root_node();
143 EXPECT_STREQ("root", root_node.name());
144 EXPECT_STREQ("default", property_info_area->context(root_node.context_index()));
145 EXPECT_STREQ("default", property_info_area->schema(root_node.schema_index()));
146
147 const char* context;
148 const char* schema;
149 property_info_area->GetPropertyInfo("abc", &context, &schema);
150 EXPECT_STREQ("default", context);
151 EXPECT_STREQ("default", schema);
152 property_info_area->GetPropertyInfo("abc.abc", &context, &schema);
153 EXPECT_STREQ("default", context);
154 EXPECT_STREQ("default", schema);
155 property_info_area->GetPropertyInfo("123.abc", &context, &schema);
156 EXPECT_STREQ("default", context);
157 EXPECT_STREQ("default", schema);
158
159 property_info_area->GetPropertyInfo("test.a", &context, &schema);
160 EXPECT_STREQ("1st", context);
161 EXPECT_STREQ("1st", schema);
162 property_info_area->GetPropertyInfo("test.b", &context, &schema);
163 EXPECT_STREQ("1st", context);
164 EXPECT_STREQ("1st", schema);
165 property_info_area->GetPropertyInfo("test.c", &context, &schema);
166 EXPECT_STREQ("1st", context);
167 EXPECT_STREQ("1st", schema);
168
169 property_info_area->GetPropertyInfo("test.test", &context, &schema);
170 EXPECT_STREQ("5th", context);
171 EXPECT_STREQ("5th", schema);
172 property_info_area->GetPropertyInfo("test.testa", &context, &schema);
173 EXPECT_STREQ("2nd", context);
174 EXPECT_STREQ("2nd", schema);
175 property_info_area->GetPropertyInfo("test.testb", &context, &schema);
176 EXPECT_STREQ("2nd", context);
177 EXPECT_STREQ("2nd", schema);
178 property_info_area->GetPropertyInfo("test.testc", &context, &schema);
179 EXPECT_STREQ("2nd", context);
180 EXPECT_STREQ("2nd", schema);
181
182 property_info_area->GetPropertyInfo("test.test.a", &context, &schema);
183 EXPECT_STREQ("2nd", context);
184 EXPECT_STREQ("2nd", schema);
185 property_info_area->GetPropertyInfo("test.test.b", &context, &schema);
186 EXPECT_STREQ("2nd", context);
187 EXPECT_STREQ("2nd", schema);
188 property_info_area->GetPropertyInfo("test.test.c", &context, &schema);
189 EXPECT_STREQ("2nd", context);
190 EXPECT_STREQ("2nd", schema);
191
192 property_info_area->GetPropertyInfo("test.test1", &context, &schema);
193 EXPECT_STREQ("3rd", context);
194 EXPECT_STREQ("3rd", schema);
195 property_info_area->GetPropertyInfo("test.test2", &context, &schema);
196 EXPECT_STREQ("7th", context);
197 EXPECT_STREQ("7th", schema);
198 property_info_area->GetPropertyInfo("test.test3", &context, &schema);
199 EXPECT_STREQ("3rd", context);
200 EXPECT_STREQ("3rd", schema);
201
202 property_info_area->GetPropertyInfo("test.test11", &context, &schema);
203 EXPECT_STREQ("2nd", context);
204 EXPECT_STREQ("2nd", schema);
205 property_info_area->GetPropertyInfo("test.test22", &context, &schema);
206 EXPECT_STREQ("2nd", context);
207 EXPECT_STREQ("2nd", schema);
208 property_info_area->GetPropertyInfo("test.test33", &context, &schema);
209 EXPECT_STREQ("2nd", context);
210 EXPECT_STREQ("2nd", schema);
211
212 property_info_area->GetPropertyInfo("this.is.a.long.string", &context, &schema);
213 EXPECT_STREQ("4th", context);
214 EXPECT_STREQ("4th", schema);
215
216 property_info_area->GetPropertyInfo("this.is.a.long", &context, &schema);
217 EXPECT_STREQ("default", context);
218 EXPECT_STREQ("default", schema);
219 property_info_area->GetPropertyInfo("this.is.a", &context, &schema);
220 EXPECT_STREQ("default", context);
221 EXPECT_STREQ("default", schema);
222 property_info_area->GetPropertyInfo("this.is", &context, &schema);
223 EXPECT_STREQ("default", context);
224 EXPECT_STREQ("default", schema);
225 property_info_area->GetPropertyInfo("this", &context, &schema);
226 EXPECT_STREQ("default", context);
227 EXPECT_STREQ("default", schema);
228
229 property_info_area->GetPropertyInfo("test.test2.a", &context, &schema);
230 EXPECT_STREQ("6th", context);
231 EXPECT_STREQ("6th", schema);
232}
233
234TEST(propertyinfoserializer, RealProperties) {
235 auto property_info = std::vector<PropertyInfoEntry>{
236 // Contexts from system/sepolicy/private/property_contexts
237 {"net.rmnet", "u:object_r:net_radio_prop:s0", "string", false},
238 {"net.gprs", "u:object_r:net_radio_prop:s0", "string", false},
239 {"net.ppp", "u:object_r:net_radio_prop:s0", "string", false},
240 {"net.qmi", "u:object_r:net_radio_prop:s0", "string", false},
241 {"net.lte", "u:object_r:net_radio_prop:s0", "string", false},
242 {"net.cdma", "u:object_r:net_radio_prop:s0", "string", false},
243 {"net.dns", "u:object_r:net_dns_prop:s0", "string", false},
244 {"sys.usb.config", "u:object_r:system_radio_prop:s0", "string", false},
245 {"ril.", "u:object_r:radio_prop:s0", "string", false},
246 {"ro.ril.", "u:object_r:radio_prop:s0", "string", false},
247 {"gsm.", "u:object_r:radio_prop:s0", "string", false},
248 {"persist.radio", "u:object_r:radio_prop:s0", "string", false},
249
250 {"net.", "u:object_r:system_prop:s0", "string", false},
251 {"dev.", "u:object_r:system_prop:s0", "string", false},
252 {"ro.runtime.", "u:object_r:system_prop:s0", "string", false},
253 {"ro.runtime.firstboot", "u:object_r:firstboot_prop:s0", "string", false},
254 {"hw.", "u:object_r:system_prop:s0", "string", false},
255 {"ro.hw.", "u:object_r:system_prop:s0", "string", false},
256 {"sys.", "u:object_r:system_prop:s0", "string", false},
257 {"sys.cppreopt", "u:object_r:cppreopt_prop:s0", "string", false},
258 {"sys.powerctl", "u:object_r:powerctl_prop:s0", "string", false},
259 {"sys.usb.ffs.", "u:object_r:ffs_prop:s0", "string", false},
260 {"service.", "u:object_r:system_prop:s0", "string", false},
261 {"dhcp.", "u:object_r:dhcp_prop:s0", "string", false},
262 {"dhcp.bt-pan.result", "u:object_r:pan_result_prop:s0", "string", false},
263 {"bluetooth.", "u:object_r:bluetooth_prop:s0", "string", false},
264
265 {"debug.", "u:object_r:debug_prop:s0", "string", false},
266 {"debug.db.", "u:object_r:debuggerd_prop:s0", "string", false},
267 {"dumpstate.", "u:object_r:dumpstate_prop:s0", "string", false},
268 {"dumpstate.options", "u:object_r:dumpstate_options_prop:s0", "string", false},
269 {"log.", "u:object_r:log_prop:s0", "string", false},
270 {"log.tag", "u:object_r:log_tag_prop:s0", "string", false},
271 {"log.tag.WifiHAL", "u:object_r:wifi_log_prop:s0", "string", false},
272 {"security.perf_harden", "u:object_r:shell_prop:s0", "string", false},
273 {"service.adb.root", "u:object_r:shell_prop:s0", "string", false},
274 {"service.adb.tcp.port", "u:object_r:shell_prop:s0", "string", false},
275
276 {"persist.audio.", "u:object_r:audio_prop:s0", "string", false},
277 {"persist.bluetooth.", "u:object_r:bluetooth_prop:s0", "string", false},
278 {"persist.debug.", "u:object_r:persist_debug_prop:s0", "string", false},
279 {"persist.logd.", "u:object_r:logd_prop:s0", "string", false},
280 {"persist.logd.security", "u:object_r:device_logging_prop:s0", "string", false},
281 {"persist.logd.logpersistd", "u:object_r:logpersistd_logging_prop:s0", "string", false},
282 {"logd.logpersistd", "u:object_r:logpersistd_logging_prop:s0", "string", false},
283 {"persist.log.tag", "u:object_r:log_tag_prop:s0", "string", false},
284 {"persist.mmc.", "u:object_r:mmc_prop:s0", "string", false},
285 {"persist.netd.stable_secret", "u:object_r:netd_stable_secret_prop:s0", "string", false},
286 {"persist.sys.", "u:object_r:system_prop:s0", "string", false},
287 {"persist.sys.safemode", "u:object_r:safemode_prop:s0", "string", false},
288 {"ro.sys.safemode", "u:object_r:safemode_prop:s0", "string", false},
289 {"persist.sys.audit_safemode", "u:object_r:safemode_prop:s0", "string", false},
290 {"persist.service.", "u:object_r:system_prop:s0", "string", false},
291 {"persist.service.bdroid.", "u:object_r:bluetooth_prop:s0", "string", false},
292 {"persist.security.", "u:object_r:system_prop:s0", "string", false},
293 {"persist.vendor.overlay.", "u:object_r:overlay_prop:s0", "string", false},
294 {"ro.boot.vendor.overlay.", "u:object_r:overlay_prop:s0", "string", false},
295 {"ro.boottime.", "u:object_r:boottime_prop:s0", "string", false},
296 {"ro.serialno", "u:object_r:serialno_prop:s0", "string", false},
297 {"ro.boot.btmacaddr", "u:object_r:bluetooth_prop:s0", "string", false},
298 {"ro.boot.serialno", "u:object_r:serialno_prop:s0", "string", false},
299 {"ro.bt.", "u:object_r:bluetooth_prop:s0", "string", false},
300 {"ro.boot.bootreason", "u:object_r:bootloader_boot_reason_prop:s0", "string", false},
301 {"persist.sys.boot.reason", "u:object_r:last_boot_reason_prop:s0", "string", false},
302 {"sys.boot.reason", "u:object_r:system_boot_reason_prop:s0", "string", false},
303 {"ro.device_owner", "u:object_r:device_logging_prop:s0", "string", false},
304
305 {"selinux.restorecon_recursive", "u:object_r:restorecon_prop:s0", "string", false},
306
307 {"vold.", "u:object_r:vold_prop:s0", "string", false},
308 {"ro.crypto.", "u:object_r:vold_prop:s0", "string", false},
309
310 {"ro.build.fingerprint", "u:object_r:fingerprint_prop:s0", "string", false},
311
312 {"ro.persistent_properties.ready", "u:object_r:persistent_properties_ready_prop:s0", "string",
313 false},
314
315 {"ctl.bootanim", "u:object_r:ctl_bootanim_prop:s0", "string", false},
316 {"ctl.dumpstate", "u:object_r:ctl_dumpstate_prop:s0", "string", false},
317 {"ctl.fuse_", "u:object_r:ctl_fuse_prop:s0", "string", false},
318 {"ctl.mdnsd", "u:object_r:ctl_mdnsd_prop:s0", "string", false},
319 {"ctl.ril-daemon", "u:object_r:ctl_rildaemon_prop:s0", "string", false},
320 {"ctl.bugreport", "u:object_r:ctl_bugreport_prop:s0", "string", false},
321 {"ctl.console", "u:object_r:ctl_console_prop:s0", "string", false},
322 {"ctl.", "u:object_r:ctl_default_prop:s0", "string", false},
323
324 {"nfc.", "u:object_r:nfc_prop:s0", "string", false},
325
326 {"config.", "u:object_r:config_prop:s0", "string", false},
327 {"ro.config.", "u:object_r:config_prop:s0", "string", false},
328 {"dalvik.", "u:object_r:dalvik_prop:s0", "string", false},
329 {"ro.dalvik.", "u:object_r:dalvik_prop:s0", "string", false},
330
331 {"wlan.", "u:object_r:wifi_prop:s0", "string", false},
332
333 {"lowpan.", "u:object_r:lowpan_prop:s0", "string", false},
334 {"ro.lowpan.", "u:object_r:lowpan_prop:s0", "string", false},
335
336 {"hwservicemanager.", "u:object_r:hwservicemanager_prop:s0", "string", false},
337 // Contexts from device/lge/bullhead/sepolicy/property_contexts
338 {"wc_transport.", "u:object_r:wc_transport_prop:s0", "string", false},
339 {"sys.listeners.", "u:object_r:qseecomtee_prop:s0", "string", false},
340 {"sys.keymaster.", "u:object_r:qseecomtee_prop:s0", "string", false},
341 {"radio.atfwd.", "u:object_r:radio_atfwd_prop:s0", "string", false},
342 {"sys.ims.", "u:object_r:qcom_ims_prop:s0", "string", false},
343 {"sensors.contexthub.", "u:object_r:contexthub_prop:s0", "string", false},
344 {"net.r_rmnet", "u:object_r:net_radio_prop:s0", "string", false},
345 };
346
347 auto serialized_trie = std::string();
348 auto build_trie_error = std::string();
349 ASSERT_TRUE(BuildTrie(property_info, "u:object_r:default_prop:s0", "string", &serialized_trie,
350 &build_trie_error))
351 << build_trie_error;
352
353 auto property_info_area = reinterpret_cast<const PropertyInfoArea*>(serialized_trie.data());
354
355 auto properties_and_contexts = std::vector<std::pair<std::string, std::string>>{
356 // Actual properties on bullhead via `getprop -Z`
357 {"af.fast_track_multiplier", "u:object_r:default_prop:s0"},
358 {"audio_hal.period_size", "u:object_r:default_prop:s0"},
359 {"bluetooth.enable_timeout_ms", "u:object_r:bluetooth_prop:s0"},
360 {"dalvik.vm.appimageformat", "u:object_r:dalvik_prop:s0"},
361 {"dalvik.vm.boot-dex2oat-threads", "u:object_r:dalvik_prop:s0"},
362 {"dalvik.vm.dex2oat-Xms", "u:object_r:dalvik_prop:s0"},
363 {"dalvik.vm.dex2oat-Xmx", "u:object_r:dalvik_prop:s0"},
364 {"dalvik.vm.dex2oat-threads", "u:object_r:dalvik_prop:s0"},
365 {"dalvik.vm.dexopt.secondary", "u:object_r:dalvik_prop:s0"},
366 {"dalvik.vm.heapgrowthlimit", "u:object_r:dalvik_prop:s0"},
367 {"dalvik.vm.heapmaxfree", "u:object_r:dalvik_prop:s0"},
368 {"dalvik.vm.heapminfree", "u:object_r:dalvik_prop:s0"},
369 {"dalvik.vm.heapsize", "u:object_r:dalvik_prop:s0"},
370 {"dalvik.vm.heapstartsize", "u:object_r:dalvik_prop:s0"},
371 {"dalvik.vm.heaptargetutilization", "u:object_r:dalvik_prop:s0"},
372 {"dalvik.vm.image-dex2oat-Xms", "u:object_r:dalvik_prop:s0"},
373 {"dalvik.vm.image-dex2oat-Xmx", "u:object_r:dalvik_prop:s0"},
374 {"dalvik.vm.image-dex2oat-threads", "u:object_r:dalvik_prop:s0"},
375 {"dalvik.vm.isa.arm.features", "u:object_r:dalvik_prop:s0"},
376 {"dalvik.vm.isa.arm.variant", "u:object_r:dalvik_prop:s0"},
377 {"dalvik.vm.isa.arm64.features", "u:object_r:dalvik_prop:s0"},
378 {"dalvik.vm.isa.arm64.variant", "u:object_r:dalvik_prop:s0"},
379 {"dalvik.vm.lockprof.threshold", "u:object_r:dalvik_prop:s0"},
380 {"dalvik.vm.stack-trace-file", "u:object_r:dalvik_prop:s0"},
381 {"dalvik.vm.usejit", "u:object_r:dalvik_prop:s0"},
382 {"dalvik.vm.usejitprofiles", "u:object_r:dalvik_prop:s0"},
383 {"debug.atrace.tags.enableflags", "u:object_r:debug_prop:s0"},
384 {"debug.force_rtl", "u:object_r:debug_prop:s0"},
385 {"dev.bootcomplete", "u:object_r:system_prop:s0"},
386 {"drm.service.enabled", "u:object_r:default_prop:s0"},
387 {"gsm.current.phone-type", "u:object_r:radio_prop:s0"},
388 {"gsm.network.type", "u:object_r:radio_prop:s0"},
389 {"gsm.operator.alpha", "u:object_r:radio_prop:s0"},
390 {"gsm.operator.iso-country", "u:object_r:radio_prop:s0"},
391 {"gsm.operator.isroaming", "u:object_r:radio_prop:s0"},
392 {"gsm.operator.numeric", "u:object_r:radio_prop:s0"},
393 {"gsm.sim.operator.alpha", "u:object_r:radio_prop:s0"},
394 {"gsm.sim.operator.iso-country", "u:object_r:radio_prop:s0"},
395 {"gsm.sim.operator.numeric", "u:object_r:radio_prop:s0"},
396 {"gsm.sim.state", "u:object_r:radio_prop:s0"},
397 {"gsm.version.baseband", "u:object_r:radio_prop:s0"},
398 {"gsm.version.ril-impl", "u:object_r:radio_prop:s0"},
399 {"hwservicemanager.ready", "u:object_r:hwservicemanager_prop:s0"},
400 {"init.svc.adbd", "u:object_r:default_prop:s0"},
401 {"init.svc.atfwd", "u:object_r:default_prop:s0"},
402 {"init.svc.audioserver", "u:object_r:default_prop:s0"},
403 {"init.svc.bootanim", "u:object_r:default_prop:s0"},
404 {"init.svc.bullhead-sh", "u:object_r:default_prop:s0"},
405 {"init.svc.cameraserver", "u:object_r:default_prop:s0"},
406 {"init.svc.cnd", "u:object_r:default_prop:s0"},
407 {"init.svc.cnss-daemon", "u:object_r:default_prop:s0"},
408 {"init.svc.cnss_diag", "u:object_r:default_prop:s0"},
409 {"init.svc.configstore-hal-1-0", "u:object_r:default_prop:s0"},
410 {"init.svc.console", "u:object_r:default_prop:s0"},
411 {"init.svc.devstart_sh", "u:object_r:default_prop:s0"},
412 {"init.svc.drm", "u:object_r:default_prop:s0"},
413 {"init.svc.dumpstate-1-0", "u:object_r:default_prop:s0"},
414 {"init.svc.flash-nanohub-fw", "u:object_r:default_prop:s0"},
415 {"init.svc.fps_hal", "u:object_r:default_prop:s0"},
416 {"init.svc.gatekeeperd", "u:object_r:default_prop:s0"},
417 {"init.svc.gralloc-2-0", "u:object_r:default_prop:s0"},
418 {"init.svc.healthd", "u:object_r:default_prop:s0"},
419 {"init.svc.hidl_memory", "u:object_r:default_prop:s0"},
420 {"init.svc.hostapd", "u:object_r:default_prop:s0"},
421 {"init.svc.hwservicemanager", "u:object_r:default_prop:s0"},
422 {"init.svc.imsdatadaemon", "u:object_r:default_prop:s0"},
423 {"init.svc.imsqmidaemon", "u:object_r:default_prop:s0"},
424 {"init.svc.installd", "u:object_r:default_prop:s0"},
425 {"init.svc.irsc_util", "u:object_r:default_prop:s0"},
426 {"init.svc.keystore", "u:object_r:default_prop:s0"},
427 {"init.svc.lmkd", "u:object_r:default_prop:s0"},
428 {"init.svc.loc_launcher", "u:object_r:default_prop:s0"},
429 {"init.svc.logd", "u:object_r:default_prop:s0"},
430 {"init.svc.logd-reinit", "u:object_r:default_prop:s0"},
431 {"init.svc.media", "u:object_r:default_prop:s0"},
432 {"init.svc.mediadrm", "u:object_r:default_prop:s0"},
433 {"init.svc.mediaextractor", "u:object_r:default_prop:s0"},
434 {"init.svc.mediametrics", "u:object_r:default_prop:s0"},
435 {"init.svc.msm_irqbalance", "u:object_r:default_prop:s0"},
436 {"init.svc.netd", "u:object_r:default_prop:s0"},
437 {"init.svc.netmgrd", "u:object_r:default_prop:s0"},
438 {"init.svc.per_mgr", "u:object_r:default_prop:s0"},
439 {"init.svc.per_proxy", "u:object_r:default_prop:s0"},
440 {"init.svc.perfd", "u:object_r:default_prop:s0"},
441 {"init.svc.qcamerasvr", "u:object_r:default_prop:s0"},
442 {"init.svc.qmuxd", "u:object_r:default_prop:s0"},
443 {"init.svc.qseecomd", "u:object_r:default_prop:s0"},
444 {"init.svc.qti", "u:object_r:default_prop:s0"},
445 {"init.svc.ril-daemon", "u:object_r:default_prop:s0"},
446 {"init.svc.rmt_storage", "u:object_r:default_prop:s0"},
447 {"init.svc.servicemanager", "u:object_r:default_prop:s0"},
448 {"init.svc.ss_ramdump", "u:object_r:default_prop:s0"},
449 {"init.svc.start_hci_filter", "u:object_r:default_prop:s0"},
450 {"init.svc.storaged", "u:object_r:default_prop:s0"},
451 {"init.svc.surfaceflinger", "u:object_r:default_prop:s0"},
452 {"init.svc.thermal-engine", "u:object_r:default_prop:s0"},
453 {"init.svc.time_daemon", "u:object_r:default_prop:s0"},
454 {"init.svc.tombstoned", "u:object_r:default_prop:s0"},
455 {"init.svc.ueventd", "u:object_r:default_prop:s0"},
456 {"init.svc.update_engine", "u:object_r:default_prop:s0"},
457 {"init.svc.usb-hal-1-0", "u:object_r:default_prop:s0"},
458 {"init.svc.vndservicemanager", "u:object_r:default_prop:s0"},
459 {"init.svc.vold", "u:object_r:default_prop:s0"},
460 {"init.svc.webview_zygote32", "u:object_r:default_prop:s0"},
461 {"init.svc.wifi_hal_legacy", "u:object_r:default_prop:s0"},
462 {"init.svc.wificond", "u:object_r:default_prop:s0"},
463 {"init.svc.wpa_supplicant", "u:object_r:default_prop:s0"},
464 {"init.svc.zygote", "u:object_r:default_prop:s0"},
465 {"init.svc.zygote_secondary", "u:object_r:default_prop:s0"},
466 {"keyguard.no_require_sim", "u:object_r:default_prop:s0"},
467 {"log.tag.WifiHAL", "u:object_r:wifi_log_prop:s0"},
468 {"logd.logpersistd.enable", "u:object_r:logpersistd_logging_prop:s0"},
469 {"media.aac_51_output_enabled", "u:object_r:default_prop:s0"},
470 {"media.recorder.show_manufacturer_and_model", "u:object_r:default_prop:s0"},
471 {"net.bt.name", "u:object_r:system_prop:s0"},
472 {"net.lte.ims.data.enabled", "u:object_r:net_radio_prop:s0"},
473 {"net.qtaguid_enabled", "u:object_r:system_prop:s0"},
474 {"net.tcp.default_init_rwnd", "u:object_r:system_prop:s0"},
475 {"nfc.initialized", "u:object_r:nfc_prop:s0"},
476 {"persist.audio.fluence.speaker", "u:object_r:audio_prop:s0"},
477 {"persist.audio.fluence.voicecall", "u:object_r:audio_prop:s0"},
478 {"persist.audio.fluence.voicecomm", "u:object_r:audio_prop:s0"},
479 {"persist.audio.fluence.voicerec", "u:object_r:audio_prop:s0"},
480 {"persist.camera.tnr.preview", "u:object_r:default_prop:s0"},
481 {"persist.camera.tnr.video", "u:object_r:default_prop:s0"},
482 {"persist.data.iwlan.enable", "u:object_r:default_prop:s0"},
483 {"persist.hwc.mdpcomp.enable", "u:object_r:default_prop:s0"},
484 {"persist.logd.logpersistd", "u:object_r:logpersistd_logging_prop:s0"},
485 {"persist.media.treble_omx", "u:object_r:default_prop:s0"},
486 {"persist.qcril.disable_retry", "u:object_r:default_prop:s0"},
487 {"persist.radio.adb_log_on", "u:object_r:radio_prop:s0"},
488 {"persist.radio.always_send_plmn", "u:object_r:radio_prop:s0"},
489 {"persist.radio.apm_sim_not_pwdn", "u:object_r:radio_prop:s0"},
490 {"persist.radio.custom_ecc", "u:object_r:radio_prop:s0"},
491 {"persist.radio.data_con_rprt", "u:object_r:radio_prop:s0"},
492 {"persist.radio.data_no_toggle", "u:object_r:radio_prop:s0"},
493 {"persist.radio.eons.enabled", "u:object_r:radio_prop:s0"},
494 {"persist.radio.eri64_as_home", "u:object_r:radio_prop:s0"},
495 {"persist.radio.mode_pref_nv10", "u:object_r:radio_prop:s0"},
496 {"persist.radio.process_sups_ind", "u:object_r:radio_prop:s0"},
497 {"persist.radio.redir_party_num", "u:object_r:radio_prop:s0"},
498 {"persist.radio.ril_payload_on", "u:object_r:radio_prop:s0"},
499 {"persist.radio.snapshot_enabled", "u:object_r:radio_prop:s0"},
500 {"persist.radio.snapshot_timer", "u:object_r:radio_prop:s0"},
501 {"persist.radio.use_cc_names", "u:object_r:radio_prop:s0"},
502 {"persist.speaker.prot.enable", "u:object_r:default_prop:s0"},
503 {"persist.sys.boot.reason", "u:object_r:last_boot_reason_prop:s0"},
504 {"persist.sys.dalvik.vm.lib.2", "u:object_r:system_prop:s0"},
505 {"persist.sys.debug.color_temp", "u:object_r:system_prop:s0"},
506 {"persist.sys.preloads.file_cache_expired", "u:object_r:system_prop:s0"},
507 {"persist.sys.timezone", "u:object_r:system_prop:s0"},
508 {"persist.sys.usb.config", "u:object_r:system_prop:s0"},
509 {"persist.sys.webview.vmsize", "u:object_r:system_prop:s0"},
510 {"persist.tom", "u:object_r:default_prop:s0"},
511 {"persist.tom2", "u:object_r:default_prop:s0"},
512 {"pm.dexopt.ab-ota", "u:object_r:default_prop:s0"},
513 {"pm.dexopt.bg-dexopt", "u:object_r:default_prop:s0"},
514 {"pm.dexopt.boot", "u:object_r:default_prop:s0"},
515 {"pm.dexopt.first-boot", "u:object_r:default_prop:s0"},
516 {"pm.dexopt.install", "u:object_r:default_prop:s0"},
517 {"qcom.bluetooth.soc", "u:object_r:default_prop:s0"},
518 {"radio.atfwd.start", "u:object_r:radio_atfwd_prop:s0"},
519 {"ril.ecclist", "u:object_r:radio_prop:s0"},
520 {"ril.nosim.ecc_list_1", "u:object_r:radio_prop:s0"},
521 {"ril.nosim.ecc_list_count", "u:object_r:radio_prop:s0"},
522 {"ril.qcril_pre_init_lock_held", "u:object_r:radio_prop:s0"},
523 {"rild.libpath", "u:object_r:default_prop:s0"},
524 {"ro.allow.mock.location", "u:object_r:default_prop:s0"},
525 {"ro.audio.flinger_standbytime_ms", "u:object_r:default_prop:s0"},
526 {"ro.baseband", "u:object_r:default_prop:s0"},
527 {"ro.bionic.ld.warning", "u:object_r:default_prop:s0"},
528 {"ro.board.platform", "u:object_r:default_prop:s0"},
529 {"ro.boot.baseband", "u:object_r:default_prop:s0"},
530 {"ro.boot.bootloader", "u:object_r:default_prop:s0"},
531 {"ro.boot.bootreason", "u:object_r:bootloader_boot_reason_prop:s0"},
532 {"ro.boot.dlcomplete", "u:object_r:default_prop:s0"},
533 {"ro.boot.emmc", "u:object_r:default_prop:s0"},
534 {"ro.boot.flash.locked", "u:object_r:default_prop:s0"},
535 {"ro.boot.hardware", "u:object_r:default_prop:s0"},
536 {"ro.boot.hardware.sku", "u:object_r:default_prop:s0"},
537 {"ro.boot.revision", "u:object_r:default_prop:s0"},
538 {"ro.boot.serialno", "u:object_r:serialno_prop:s0"},
539 {"ro.boot.verifiedbootstate", "u:object_r:default_prop:s0"},
540 {"ro.boot.veritymode", "u:object_r:default_prop:s0"},
541 {"ro.boot.wificountrycode", "u:object_r:default_prop:s0"},
542 {"ro.bootimage.build.date", "u:object_r:default_prop:s0"},
543 {"ro.bootimage.build.date.utc", "u:object_r:default_prop:s0"},
544 {"ro.bootimage.build.fingerprint", "u:object_r:default_prop:s0"},
545 {"ro.bootloader", "u:object_r:default_prop:s0"},
546 {"ro.bootmode", "u:object_r:default_prop:s0"},
547 {"ro.boottime.adbd", "u:object_r:boottime_prop:s0"},
548 {"ro.boottime.atfwd", "u:object_r:boottime_prop:s0"},
549 {"ro.boottime.audioserver", "u:object_r:boottime_prop:s0"},
550 {"ro.boottime.bootanim", "u:object_r:boottime_prop:s0"},
551 {"ro.boottime.bullhead-sh", "u:object_r:boottime_prop:s0"},
552 {"ro.boottime.cameraserver", "u:object_r:boottime_prop:s0"},
553 {"ro.boottime.cnd", "u:object_r:boottime_prop:s0"},
554 {"ro.boottime.cnss-daemon", "u:object_r:boottime_prop:s0"},
555 {"ro.boottime.cnss_diag", "u:object_r:boottime_prop:s0"},
556 {"ro.boottime.configstore-hal-1-0", "u:object_r:boottime_prop:s0"},
557 {"ro.boottime.console", "u:object_r:boottime_prop:s0"},
558 {"ro.boottime.devstart_sh", "u:object_r:boottime_prop:s0"},
559 {"ro.boottime.drm", "u:object_r:boottime_prop:s0"},
560 {"ro.boottime.dumpstate-1-0", "u:object_r:boottime_prop:s0"},
561 {"ro.boottime.flash-nanohub-fw", "u:object_r:boottime_prop:s0"},
562 {"ro.boottime.fps_hal", "u:object_r:boottime_prop:s0"},
563 {"ro.boottime.gatekeeperd", "u:object_r:boottime_prop:s0"},
564 {"ro.boottime.gralloc-2-0", "u:object_r:boottime_prop:s0"},
565 {"ro.boottime.healthd", "u:object_r:boottime_prop:s0"},
566 {"ro.boottime.hidl_memory", "u:object_r:boottime_prop:s0"},
567 {"ro.boottime.hwservicemanager", "u:object_r:boottime_prop:s0"},
568 {"ro.boottime.imsdatadaemon", "u:object_r:boottime_prop:s0"},
569 {"ro.boottime.imsqmidaemon", "u:object_r:boottime_prop:s0"},
570 {"ro.boottime.init", "u:object_r:boottime_prop:s0"},
571 {"ro.boottime.init.cold_boot_wait", "u:object_r:boottime_prop:s0"},
572 {"ro.boottime.init.mount_all.default", "u:object_r:boottime_prop:s0"},
573 {"ro.boottime.init.selinux", "u:object_r:boottime_prop:s0"},
574 {"ro.boottime.installd", "u:object_r:boottime_prop:s0"},
575 {"ro.boottime.irsc_util", "u:object_r:boottime_prop:s0"},
576 {"ro.boottime.keystore", "u:object_r:boottime_prop:s0"},
577 {"ro.boottime.lmkd", "u:object_r:boottime_prop:s0"},
578 {"ro.boottime.loc_launcher", "u:object_r:boottime_prop:s0"},
579 {"ro.boottime.logd", "u:object_r:boottime_prop:s0"},
580 {"ro.boottime.logd-reinit", "u:object_r:boottime_prop:s0"},
581 {"ro.boottime.media", "u:object_r:boottime_prop:s0"},
582 {"ro.boottime.mediadrm", "u:object_r:boottime_prop:s0"},
583 {"ro.boottime.mediaextractor", "u:object_r:boottime_prop:s0"},
584 {"ro.boottime.mediametrics", "u:object_r:boottime_prop:s0"},
585 {"ro.boottime.msm_irqbalance", "u:object_r:boottime_prop:s0"},
586 {"ro.boottime.netd", "u:object_r:boottime_prop:s0"},
587 {"ro.boottime.netmgrd", "u:object_r:boottime_prop:s0"},
588 {"ro.boottime.per_mgr", "u:object_r:boottime_prop:s0"},
589 {"ro.boottime.per_proxy", "u:object_r:boottime_prop:s0"},
590 {"ro.boottime.perfd", "u:object_r:boottime_prop:s0"},
591 {"ro.boottime.qcamerasvr", "u:object_r:boottime_prop:s0"},
592 {"ro.boottime.qmuxd", "u:object_r:boottime_prop:s0"},
593 {"ro.boottime.qseecomd", "u:object_r:boottime_prop:s0"},
594 {"ro.boottime.qti", "u:object_r:boottime_prop:s0"},
595 {"ro.boottime.ril-daemon", "u:object_r:boottime_prop:s0"},
596 {"ro.boottime.rmt_storage", "u:object_r:boottime_prop:s0"},
597 {"ro.boottime.servicemanager", "u:object_r:boottime_prop:s0"},
598 {"ro.boottime.ss_ramdump", "u:object_r:boottime_prop:s0"},
599 {"ro.boottime.start_hci_filter", "u:object_r:boottime_prop:s0"},
600 {"ro.boottime.storaged", "u:object_r:boottime_prop:s0"},
601 {"ro.boottime.surfaceflinger", "u:object_r:boottime_prop:s0"},
602 {"ro.boottime.thermal-engine", "u:object_r:boottime_prop:s0"},
603 {"ro.boottime.time_daemon", "u:object_r:boottime_prop:s0"},
604 {"ro.boottime.tombstoned", "u:object_r:boottime_prop:s0"},
605 {"ro.boottime.ueventd", "u:object_r:boottime_prop:s0"},
606 {"ro.boottime.update_engine", "u:object_r:boottime_prop:s0"},
607 {"ro.boottime.usb-hal-1-0", "u:object_r:boottime_prop:s0"},
608 {"ro.boottime.vndservicemanager", "u:object_r:boottime_prop:s0"},
609 {"ro.boottime.vold", "u:object_r:boottime_prop:s0"},
610 {"ro.boottime.webview_zygote32", "u:object_r:boottime_prop:s0"},
611 {"ro.boottime.wifi_hal_legacy", "u:object_r:boottime_prop:s0"},
612 {"ro.boottime.wificond", "u:object_r:boottime_prop:s0"},
613 {"ro.boottime.zygote", "u:object_r:boottime_prop:s0"},
614 {"ro.boottime.zygote_secondary", "u:object_r:boottime_prop:s0"},
615 {"ro.bt.bdaddr_path", "u:object_r:bluetooth_prop:s0"},
616 {"ro.build.characteristics", "u:object_r:default_prop:s0"},
617 {"ro.build.date", "u:object_r:default_prop:s0"},
618 {"ro.build.date.utc", "u:object_r:default_prop:s0"},
619 {"ro.build.description", "u:object_r:default_prop:s0"},
620 {"ro.build.display.id", "u:object_r:default_prop:s0"},
621 {"ro.build.expect.baseband", "u:object_r:default_prop:s0"},
622 {"ro.build.expect.bootloader", "u:object_r:default_prop:s0"},
623 {"ro.build.fingerprint", "u:object_r:fingerprint_prop:s0"},
624 {"ro.build.flavor", "u:object_r:default_prop:s0"},
625 {"ro.build.host", "u:object_r:default_prop:s0"},
626 {"ro.build.id", "u:object_r:default_prop:s0"},
627 {"ro.build.product", "u:object_r:default_prop:s0"},
628 {"ro.build.tags", "u:object_r:default_prop:s0"},
629 {"ro.build.type", "u:object_r:default_prop:s0"},
630 {"ro.build.user", "u:object_r:default_prop:s0"},
631 {"ro.build.version.all_codenames", "u:object_r:default_prop:s0"},
632 {"ro.build.version.base_os", "u:object_r:default_prop:s0"},
633 {"ro.build.version.codename", "u:object_r:default_prop:s0"},
634 {"ro.build.version.incremental", "u:object_r:default_prop:s0"},
635 {"ro.build.version.preview_sdk", "u:object_r:default_prop:s0"},
636 {"ro.build.version.release", "u:object_r:default_prop:s0"},
637 {"ro.build.version.sdk", "u:object_r:default_prop:s0"},
638 {"ro.build.version.security_patch", "u:object_r:default_prop:s0"},
639 {"ro.camera.notify_nfc", "u:object_r:default_prop:s0"},
640 {"ro.carrier", "u:object_r:default_prop:s0"},
641 {"ro.com.android.dataroaming", "u:object_r:default_prop:s0"},
642 {"ro.config.alarm_alert", "u:object_r:config_prop:s0"},
643 {"ro.config.notification_sound", "u:object_r:config_prop:s0"},
644 {"ro.config.ringtone", "u:object_r:config_prop:s0"},
645 {"ro.config.vc_call_vol_steps", "u:object_r:config_prop:s0"},
646 {"ro.crypto.fs_crypto_blkdev", "u:object_r:vold_prop:s0"},
647 {"ro.crypto.state", "u:object_r:vold_prop:s0"},
648 {"ro.crypto.type", "u:object_r:vold_prop:s0"},
649 {"ro.dalvik.vm.native.bridge", "u:object_r:dalvik_prop:s0"},
650 {"ro.debuggable", "u:object_r:default_prop:s0"},
651 {"ro.device_owner", "u:object_r:device_logging_prop:s0"},
652 {"ro.expect.recovery_id", "u:object_r:default_prop:s0"},
653 {"ro.frp.pst", "u:object_r:default_prop:s0"},
654 {"ro.hardware", "u:object_r:default_prop:s0"},
655 {"ro.hwui.drop_shadow_cache_size", "u:object_r:default_prop:s0"},
656 {"ro.hwui.gradient_cache_size", "u:object_r:default_prop:s0"},
657 {"ro.hwui.layer_cache_size", "u:object_r:default_prop:s0"},
658 {"ro.hwui.path_cache_size", "u:object_r:default_prop:s0"},
659 {"ro.hwui.r_buffer_cache_size", "u:object_r:default_prop:s0"},
660 {"ro.hwui.text_large_cache_height", "u:object_r:default_prop:s0"},
661 {"ro.hwui.text_large_cache_width", "u:object_r:default_prop:s0"},
662 {"ro.hwui.text_small_cache_height", "u:object_r:default_prop:s0"},
663 {"ro.hwui.text_small_cache_width", "u:object_r:default_prop:s0"},
664 {"ro.hwui.texture_cache_flushrate", "u:object_r:default_prop:s0"},
665 {"ro.hwui.texture_cache_size", "u:object_r:default_prop:s0"},
666 {"ro.min_freq_0", "u:object_r:default_prop:s0"},
667 {"ro.min_freq_4", "u:object_r:default_prop:s0"},
668 {"ro.oem_unlock_supported", "u:object_r:default_prop:s0"},
669 {"ro.opengles.version", "u:object_r:default_prop:s0"},
670 {"ro.persistent_properties.ready", "u:object_r:persistent_properties_ready_prop:s0"},
671 {"ro.product.board", "u:object_r:default_prop:s0"},
672 {"ro.product.brand", "u:object_r:default_prop:s0"},
673 {"ro.product.cpu.abi", "u:object_r:default_prop:s0"},
674 {"ro.product.cpu.abilist", "u:object_r:default_prop:s0"},
675 {"ro.product.cpu.abilist32", "u:object_r:default_prop:s0"},
676 {"ro.product.cpu.abilist64", "u:object_r:default_prop:s0"},
677 {"ro.product.device", "u:object_r:default_prop:s0"},
678 {"ro.product.first_api_level", "u:object_r:default_prop:s0"},
679 {"ro.product.locale", "u:object_r:default_prop:s0"},
680 {"ro.product.manufacturer", "u:object_r:default_prop:s0"},
681 {"ro.product.model", "u:object_r:default_prop:s0"},
682 {"ro.product.name", "u:object_r:default_prop:s0"},
683 {"ro.property_service.version", "u:object_r:default_prop:s0"},
684 {"ro.qc.sdk.audio.fluencetype", "u:object_r:default_prop:s0"},
685 {"ro.recovery_id", "u:object_r:default_prop:s0"},
686 {"ro.revision", "u:object_r:default_prop:s0"},
687 {"ro.ril.svdo", "u:object_r:radio_prop:s0"},
688 {"ro.ril.svlte1x", "u:object_r:radio_prop:s0"},
689 {"ro.runtime.firstboot", "u:object_r:firstboot_prop:s0"},
690 {"ro.secure", "u:object_r:default_prop:s0"},
691 {"ro.serialno", "u:object_r:serialno_prop:s0"},
692 {"ro.sf.lcd_density", "u:object_r:default_prop:s0"},
693 {"ro.telephony.call_ring.multiple", "u:object_r:default_prop:s0"},
694 {"ro.telephony.default_cdma_sub", "u:object_r:default_prop:s0"},
695 {"ro.telephony.default_network", "u:object_r:default_prop:s0"},
696 {"ro.treble.enabled", "u:object_r:default_prop:s0"},
697 {"ro.vendor.build.date", "u:object_r:default_prop:s0"},
698 {"ro.vendor.build.date.utc", "u:object_r:default_prop:s0"},
699 {"ro.vendor.build.fingerprint", "u:object_r:default_prop:s0"},
700 {"ro.vendor.extension_library", "u:object_r:default_prop:s0"},
701 {"ro.wifi.channels", "u:object_r:default_prop:s0"},
702 {"ro.zygote", "u:object_r:default_prop:s0"},
703 {"security.perf_harden", "u:object_r:shell_prop:s0"},
704 {"sensors.contexthub.lid_state", "u:object_r:contexthub_prop:s0"},
705 {"service.adb.root", "u:object_r:shell_prop:s0"},
706 {"service.bootanim.exit", "u:object_r:system_prop:s0"},
707 {"service.sf.present_timestamp", "u:object_r:system_prop:s0"},
708 {"sys.boot.reason", "u:object_r:system_boot_reason_prop:s0"},
709 {"sys.boot_completed", "u:object_r:system_prop:s0"},
710 {"sys.ims.QMI_DAEMON_STATUS", "u:object_r:qcom_ims_prop:s0"},
711 {"sys.listeners.registered", "u:object_r:qseecomtee_prop:s0"},
712 {"sys.logbootcomplete", "u:object_r:system_prop:s0"},
713 {"sys.oem_unlock_allowed", "u:object_r:system_prop:s0"},
714 {"sys.qcom.devup", "u:object_r:system_prop:s0"},
715 {"sys.sysctl.extra_free_kbytes", "u:object_r:system_prop:s0"},
716 {"sys.usb.config", "u:object_r:system_radio_prop:s0"},
717 {"sys.usb.configfs", "u:object_r:system_radio_prop:s0"},
718 {"sys.usb.controller", "u:object_r:system_prop:s0"},
719 {"sys.usb.ffs.aio_compat", "u:object_r:ffs_prop:s0"},
720 {"sys.usb.ffs.max_read", "u:object_r:ffs_prop:s0"},
721 {"sys.usb.ffs.max_write", "u:object_r:ffs_prop:s0"},
722 {"sys.usb.ffs.ready", "u:object_r:ffs_prop:s0"},
723 {"sys.usb.mtp.device_type", "u:object_r:system_prop:s0"},
724 {"sys.usb.state", "u:object_r:system_prop:s0"},
725 {"telephony.lteOnCdmaDevice", "u:object_r:default_prop:s0"},
726 {"tombstoned.max_tombstone_count", "u:object_r:default_prop:s0"},
727 {"vidc.debug.perf.mode", "u:object_r:default_prop:s0"},
728 {"vidc.enc.dcvs.extra-buff-count", "u:object_r:default_prop:s0"},
729 {"vold.decrypt", "u:object_r:vold_prop:s0"},
730 {"vold.has_adoptable", "u:object_r:vold_prop:s0"},
731 {"vold.post_fs_data_done", "u:object_r:vold_prop:s0"},
732 {"wc_transport.clean_up", "u:object_r:wc_transport_prop:s0"},
733 {"wc_transport.hci_filter_status", "u:object_r:wc_transport_prop:s0"},
734 {"wc_transport.ref_count", "u:object_r:wc_transport_prop:s0"},
735 {"wc_transport.soc_initialized", "u:object_r:wc_transport_prop:s0"},
736 {"wc_transport.start_hci", "u:object_r:wc_transport_prop:s0"},
737 {"wc_transport.vnd_power", "u:object_r:wc_transport_prop:s0"},
738 {"wifi.interface", "u:object_r:default_prop:s0"},
739 {"wifi.supplicant_scan_interval", "u:object_r:default_prop:s0"},
740 };
741
742 for (const auto& [property, context] : properties_and_contexts) {
743 const char* returned_context;
744 property_info_area->GetPropertyInfo(property.c_str(), &returned_context, nullptr);
745 EXPECT_EQ(context, returned_context) << property;
746 }
747}
748
749} // namespace properties
750} // namespace android
diff --git a/property_service/libpropertyinfoserializer/trie_builder.cpp b/property_service/libpropertyinfoserializer/trie_builder.cpp
new file mode 100644
index 000000000..feb753be7
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/trie_builder.cpp
@@ -0,0 +1,105 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "trie_builder.h"
18
19#include <android-base/strings.h>
20
21using android::base::Split;
22
23namespace android {
24namespace properties {
25
26TrieBuilder::TrieBuilder(const std::string& default_context, const std::string& default_schema)
27 : builder_root_("root") {
28 auto* context_pointer = StringPointerFromContainer(default_context, &contexts_);
29 builder_root_.set_context(context_pointer);
30 auto* schema_pointer = StringPointerFromContainer(default_schema, &schemas_);
31 builder_root_.set_schema(schema_pointer);
32}
33
34bool TrieBuilder::AddToTrie(const std::string& name, const std::string& context,
35 const std::string& schema, bool exact, std::string* error) {
36 auto* context_pointer = StringPointerFromContainer(context, &contexts_);
37 auto* schema_pointer = StringPointerFromContainer(schema, &schemas_);
38 return AddToTrie(name, context_pointer, schema_pointer, exact, error);
39}
40
41bool TrieBuilder::AddToTrie(const std::string& name, const std::string* context,
42 const std::string* schema, bool exact, std::string* error) {
43 TrieBuilderNode* current_node = &builder_root_;
44
45 auto name_pieces = Split(name, ".");
46
47 bool ends_with_dot = false;
48 if (name_pieces.back().empty()) {
49 ends_with_dot = true;
50 name_pieces.pop_back();
51 }
52
53 // Move us to the final node that we care about, adding incremental nodes if necessary.
54 while (name_pieces.size() > 1) {
55 auto child = current_node->FindChild(name_pieces.front());
56 if (child == nullptr) {
57 child = current_node->AddChild(name_pieces.front());
58 }
59 if (child == nullptr) {
60 *error = "Unable to allocate Trie node";
61 return false;
62 }
63 current_node = child;
64 name_pieces.erase(name_pieces.begin());
65 }
66
67 // Store our context based on what type of match it is.
68 if (exact) {
69 if (!current_node->AddExactMatchContext(name_pieces.front(), context, schema)) {
70 *error = "Duplicate exact match detected for '" + name + "'";
71 return false;
72 }
73 } else if (!ends_with_dot) {
74 if (!current_node->AddPrefixContext(name_pieces.front(), context, schema)) {
75 *error = "Duplicate prefix match detected for '" + name + "'";
76 return false;
77 }
78 } else {
79 auto child = current_node->FindChild(name_pieces.front());
80 if (child == nullptr) {
81 child = current_node->AddChild(name_pieces.front());
82 }
83 if (child == nullptr) {
84 *error = "Unable to allocate Trie node";
85 return false;
86 }
87 if (child->context() != nullptr || child->schema() != nullptr) {
88 *error = "Duplicate prefix match detected for '" + name + "'";
89 return false;
90 }
91 child->set_context(context);
92 child->set_schema(schema);
93 }
94 return true;
95}
96
97const std::string* TrieBuilder::StringPointerFromContainer(const std::string& string,
98 std::set<std::string>* container) {
99 // Get a pointer to the string in a given set, such that we only ever serialize each string once.
100 auto [iterator, _] = container->emplace(string);
101 return &(*iterator);
102}
103
104} // namespace properties
105} // namespace android
diff --git a/property_service/libpropertyinfoserializer/trie_builder.h b/property_service/libpropertyinfoserializer/trie_builder.h
new file mode 100644
index 000000000..f928e764f
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/trie_builder.h
@@ -0,0 +1,124 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#ifndef PROPERTY_INFO_SERIALIZER_TRIE_BUILDER_H
18#define PROPERTY_INFO_SERIALIZER_TRIE_BUILDER_H
19
20#include <memory>
21#include <set>
22#include <string>
23#include <vector>
24
25namespace android {
26namespace properties {
27
28struct PropertyEntryBuilder {
29 PropertyEntryBuilder() : context(nullptr), schema(nullptr) {}
30 PropertyEntryBuilder(const std::string& name, const std::string* context,
31 const std::string* schema)
32 : name(name), context(context), schema(schema) {}
33 std::string name;
34 const std::string* context;
35 const std::string* schema;
36};
37
38class TrieBuilderNode {
39 public:
40 TrieBuilderNode(const std::string& name) : property_entry_(name, nullptr, nullptr) {}
41
42 TrieBuilderNode* FindChild(const std::string& name) {
43 for (auto& child : children_) {
44 if (child.name() == name) return &child;
45 }
46 return nullptr;
47 }
48
49 const TrieBuilderNode* FindChild(const std::string& name) const {
50 for (const auto& child : children_) {
51 if (child.name() == name) return &child;
52 }
53 return nullptr;
54 }
55
56 TrieBuilderNode* AddChild(const std::string& name) { return &children_.emplace_back(name); }
57
58 bool AddPrefixContext(const std::string& prefix, const std::string* context,
59 const std::string* schema) {
60 if (std::find_if(prefixes_.begin(), prefixes_.end(),
61 [&prefix](const auto& t) { return t.name == prefix; }) != prefixes_.end()) {
62 return false;
63 }
64
65 prefixes_.emplace_back(prefix, context, schema);
66 return true;
67 }
68
69 bool AddExactMatchContext(const std::string& exact_match, const std::string* context,
70 const std::string* schema) {
71 if (std::find_if(exact_matches_.begin(), exact_matches_.end(), [&exact_match](const auto& t) {
72 return t.name == exact_match;
73 }) != exact_matches_.end()) {
74 return false;
75 }
76
77 exact_matches_.emplace_back(exact_match, context, schema);
78 return true;
79 }
80
81 const std::string& name() const { return property_entry_.name; }
82 const std::string* context() const { return property_entry_.context; }
83 void set_context(const std::string* context) { property_entry_.context = context; }
84 const std::string* schema() const { return property_entry_.schema; }
85 void set_schema(const std::string* schema) { property_entry_.schema = schema; }
86
87 const PropertyEntryBuilder property_entry() const { return property_entry_; }
88
89 const std::vector<TrieBuilderNode>& children() const { return children_; }
90 const std::vector<PropertyEntryBuilder>& prefixes() const { return prefixes_; }
91 const std::vector<PropertyEntryBuilder>& exact_matches() const { return exact_matches_; }
92
93 private:
94 PropertyEntryBuilder property_entry_;
95 std::vector<TrieBuilderNode> children_;
96 std::vector<PropertyEntryBuilder> prefixes_;
97 std::vector<PropertyEntryBuilder> exact_matches_;
98};
99
100class TrieBuilder {
101 public:
102 TrieBuilder(const std::string& default_context, const std::string& default_schema);
103 bool AddToTrie(const std::string& name, const std::string& context, const std::string& schema,
104 bool exact, std::string* error);
105
106 const TrieBuilderNode builder_root() const { return builder_root_; }
107 const std::set<std::string>& contexts() const { return contexts_; }
108 const std::set<std::string>& schemas() const { return schemas_; }
109
110 private:
111 bool AddToTrie(const std::string& name, const std::string* context, const std::string* schema,
112 bool exact, std::string* error);
113 const std::string* StringPointerFromContainer(const std::string& string,
114 std::set<std::string>* container);
115
116 TrieBuilderNode builder_root_;
117 std::set<std::string> contexts_;
118 std::set<std::string> schemas_;
119};
120
121} // namespace properties
122} // namespace android
123
124#endif
diff --git a/property_service/libpropertyinfoserializer/trie_builder_test.cpp b/property_service/libpropertyinfoserializer/trie_builder_test.cpp
new file mode 100644
index 000000000..2b948f3b0
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/trie_builder_test.cpp
@@ -0,0 +1,129 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "trie_builder.h"
18
19#include <gtest/gtest.h>
20
21namespace android {
22namespace properties {
23
24TEST(propertyinfoserializer, BuildTrie_Simple) {
25 auto trie_builder = TrieBuilder("default", "default_schema");
26
27 // Add test data to tree
28 auto error = std::string();
29 EXPECT_TRUE(trie_builder.AddToTrie("test.", "1st", "1st_schema", false, &error));
30 EXPECT_TRUE(trie_builder.AddToTrie("test.test", "2nd", "2nd_schema", false, &error));
31 EXPECT_TRUE(trie_builder.AddToTrie("test.test1", "3rd", "3rd_schema", true, &error));
32 EXPECT_TRUE(trie_builder.AddToTrie("test.test2", "3rd", "3rd_schema", true, &error));
33 EXPECT_TRUE(trie_builder.AddToTrie("test.test3", "3rd", "3rd_schema", true, &error));
34 EXPECT_TRUE(trie_builder.AddToTrie("this.is.a.long.string", "4th", "4th_schema", true, &error));
35
36 ASSERT_EQ(5U, trie_builder.contexts().size());
37 ASSERT_EQ(5U, trie_builder.schemas().size());
38
39 auto& builder_root = trie_builder.builder_root();
40
41 // Check the root node
42 EXPECT_EQ("root", builder_root.name());
43 ASSERT_NE(nullptr, builder_root.context());
44 EXPECT_EQ("default", *builder_root.context());
45 ASSERT_NE(nullptr, builder_root.schema());
46 EXPECT_EQ("default_schema", *builder_root.schema());
47
48 EXPECT_EQ(0U, builder_root.prefixes().size());
49 EXPECT_EQ(0U, builder_root.exact_matches().size());
50
51 ASSERT_EQ(2U, builder_root.children().size());
52
53 // Check the 'test.' node
54 auto* test_node = builder_root.FindChild("test");
55 EXPECT_EQ("test", test_node->name());
56 ASSERT_NE(nullptr, test_node->context());
57 EXPECT_EQ("1st", *test_node->context());
58 ASSERT_NE(nullptr, test_node->schema());
59 EXPECT_EQ("1st_schema", *test_node->schema());
60
61 EXPECT_EQ(0U, test_node->children().size());
62 EXPECT_EQ(1U, test_node->prefixes().size());
63 {
64 auto& property_entry = test_node->prefixes()[0];
65 EXPECT_EQ("test", property_entry.name);
66 ASSERT_NE(nullptr, property_entry.context);
67 EXPECT_EQ("2nd", *property_entry.context);
68 ASSERT_NE(nullptr, property_entry.schema);
69 EXPECT_EQ("2nd_schema", *property_entry.schema);
70 }
71 EXPECT_EQ(3U, test_node->exact_matches().size());
72 EXPECT_EQ("test1", test_node->exact_matches()[0].name);
73 EXPECT_EQ("test2", test_node->exact_matches()[1].name);
74 EXPECT_EQ("test3", test_node->exact_matches()[2].name);
75
76 ASSERT_NE(nullptr, test_node->exact_matches()[0].context);
77 ASSERT_NE(nullptr, test_node->exact_matches()[1].context);
78 ASSERT_NE(nullptr, test_node->exact_matches()[2].context);
79 EXPECT_EQ("3rd", *test_node->exact_matches()[0].context);
80 EXPECT_EQ("3rd", *test_node->exact_matches()[1].context);
81 EXPECT_EQ("3rd", *test_node->exact_matches()[2].context);
82
83 ASSERT_NE(nullptr, test_node->exact_matches()[0].schema);
84 ASSERT_NE(nullptr, test_node->exact_matches()[1].schema);
85 ASSERT_NE(nullptr, test_node->exact_matches()[2].schema);
86 EXPECT_EQ("3rd_schema", *test_node->exact_matches()[0].schema);
87 EXPECT_EQ("3rd_schema", *test_node->exact_matches()[1].schema);
88 EXPECT_EQ("3rd_schema", *test_node->exact_matches()[2].schema);
89
90 // Check the long string node
91 auto expect_empty_one_child = [](auto* node) {
92 ASSERT_NE(nullptr, node);
93 EXPECT_EQ(nullptr, node->context());
94 EXPECT_EQ(nullptr, node->schema());
95 EXPECT_EQ(0U, node->prefixes().size());
96 EXPECT_EQ(0U, node->exact_matches().size());
97 EXPECT_EQ(1U, node->children().size());
98 };
99
100 // Start with 'this'
101 auto* long_string_node = builder_root.FindChild("this");
102 expect_empty_one_child(long_string_node);
103
104 // Move to 'is'
105 long_string_node = long_string_node->FindChild("is");
106 expect_empty_one_child(long_string_node);
107
108 // Move to 'a'
109 long_string_node = long_string_node->FindChild("a");
110 expect_empty_one_child(long_string_node);
111
112 // Move to 'long'
113 long_string_node = long_string_node->FindChild("long");
114 EXPECT_EQ(0U, long_string_node->prefixes().size());
115 EXPECT_EQ(1U, long_string_node->exact_matches().size());
116 EXPECT_EQ(0U, long_string_node->children().size());
117
118 {
119 auto& property_entry = long_string_node->exact_matches()[0];
120 EXPECT_EQ("string", property_entry.name);
121 ASSERT_NE(nullptr, property_entry.context);
122 EXPECT_EQ("4th", *property_entry.context);
123 ASSERT_NE(nullptr, property_entry.schema);
124 EXPECT_EQ("4th_schema", *property_entry.schema);
125 }
126}
127
128} // namespace properties
129} // namespace android
diff --git a/property_service/libpropertyinfoserializer/trie_node_arena.h b/property_service/libpropertyinfoserializer/trie_node_arena.h
new file mode 100644
index 000000000..5e0ef8273
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/trie_node_arena.h
@@ -0,0 +1,108 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#ifndef PROPERTY_INFO_SERIALIZER_TRIE_NODE_ARENA_H
18#define PROPERTY_INFO_SERIALIZER_TRIE_NODE_ARENA_H
19
20#include <string>
21#include <vector>
22
23namespace android {
24namespace properties {
25
26template <typename T>
27class ArenaObjectPointer {
28 public:
29 ArenaObjectPointer(std::string& arena_data, uint32_t offset)
30 : arena_data_(arena_data), offset_(offset) {}
31
32 T* operator->() { return reinterpret_cast<T*>(arena_data_.data() + offset_); }
33
34 private:
35 std::string& arena_data_;
36 uint32_t offset_;
37};
38
39class TrieNodeArena {
40 public:
41 TrieNodeArena() : current_data_pointer_(0) {}
42
43 // We can't return pointers to objects since data_ may move when reallocated, thus invalidating
44 // any pointers. Therefore we return an ArenaObjectPointer, which always accesses elements via
45 // data_ + offset.
46 template <typename T>
47 ArenaObjectPointer<T> AllocateObject(uint32_t* return_offset) {
48 uint32_t offset;
49 AllocateData(sizeof(T), &offset);
50 if (return_offset) *return_offset = offset;
51 return ArenaObjectPointer<T>(data_, offset);
52 }
53
54 uint32_t AllocateUint32Array(int length) {
55 uint32_t offset;
56 AllocateData(sizeof(uint32_t) * length, &offset);
57 return offset;
58 }
59
60 uint32_t* uint32_array(uint32_t offset) {
61 return reinterpret_cast<uint32_t*>(data_.data() + offset);
62 }
63
64 uint32_t AllocateAndWriteString(const std::string& string) {
65 uint32_t offset;
66 char* data = static_cast<char*>(AllocateData(string.size() + 1, &offset));
67 strcpy(data, string.c_str());
68 return offset;
69 }
70
71 void AllocateAndWriteUint32(uint32_t value) {
72 auto location = static_cast<uint32_t*>(AllocateData(sizeof(uint32_t), nullptr));
73 *location = value;
74 }
75
76 void* AllocateData(size_t size, uint32_t* offset) {
77 size_t aligned_size = size + (sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1);
78
79 if (current_data_pointer_ + aligned_size > data_.size()) {
80 auto new_size = (current_data_pointer_ + aligned_size + data_.size()) * 2;
81 data_.resize(new_size, '\0');
82 }
83 if (offset) *offset = current_data_pointer_;
84
85 uint32_t return_offset = current_data_pointer_;
86 current_data_pointer_ += aligned_size;
87 return &data_[0] + return_offset;
88 }
89
90 uint32_t size() const { return current_data_pointer_; }
91
92 const std::string& data() const { return data_; }
93
94 std::string truncated_data() const {
95 auto result = data_;
96 result.resize(current_data_pointer_);
97 return result;
98 }
99
100 private:
101 std::string data_;
102 uint32_t current_data_pointer_;
103};
104
105} // namespace properties
106} // namespace android
107
108#endif
diff --git a/property_service/libpropertyinfoserializer/trie_serializer.cpp b/property_service/libpropertyinfoserializer/trie_serializer.cpp
new file mode 100644
index 000000000..5326537f4
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/trie_serializer.cpp
@@ -0,0 +1,142 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#include "trie_serializer.h"
18
19namespace android {
20namespace properties {
21
22// Serialized strings contains:
23// 1) A uint32_t count of elements in the below array
24// 2) A sorted array of uint32_t offsets pointing to null terminated strings
25// 3) Each of the null terminated strings themselves packed back to back
26// This returns the offset into arena where the serialized strings start.
27void TrieSerializer::SerializeStrings(const std::set<std::string>& strings) {
28 arena_->AllocateAndWriteUint32(strings.size());
29
30 // Allocate space for the array.
31 uint32_t offset_array_offset = arena_->AllocateUint32Array(strings.size());
32
33 // Write offset pointers and strings; these are already alphabetically sorted by virtue of being
34 // in an std::set.
35 auto it = strings.begin();
36 for (unsigned int i = 0; i < strings.size(); ++i, ++it) {
37 uint32_t string_offset = arena_->AllocateAndWriteString(*it);
38 arena_->uint32_array(offset_array_offset)[i] = string_offset;
39 }
40}
41
42uint32_t TrieSerializer::WritePropertyEntry(const PropertyEntryBuilder& property_entry) {
43 uint32_t context_index = property_entry.context != nullptr && !property_entry.context->empty()
44 ? serialized_info()->FindContextIndex(property_entry.context->c_str())
45 : ~0u;
46 uint32_t schema_index = property_entry.schema != nullptr && !property_entry.schema->empty()
47 ? serialized_info()->FindSchemaIndex(property_entry.schema->c_str())
48 : ~0u;
49 uint32_t offset;
50 auto serialized_property_entry = arena_->AllocateObject<PropertyEntry>(&offset);
51 serialized_property_entry->name_offset = arena_->AllocateAndWriteString(property_entry.name);
52 serialized_property_entry->namelen = property_entry.name.size();
53 serialized_property_entry->context_index = context_index;
54 serialized_property_entry->schema_index = schema_index;
55 return offset;
56}
57
58uint32_t TrieSerializer::WriteTrieNode(const TrieBuilderNode& builder_node) {
59 uint32_t trie_offset;
60 auto trie = arena_->AllocateObject<TrieNodeInternal>(&trie_offset);
61
62 trie->property_entry = WritePropertyEntry(builder_node.property_entry());
63
64 // Write prefix matches
65 auto sorted_prefix_matches = builder_node.prefixes();
66 // Prefixes are sorted by descending length
67 std::sort(sorted_prefix_matches.begin(), sorted_prefix_matches.end(),
68 [](const auto& lhs, const auto& rhs) { return lhs.name.size() > rhs.name.size(); });
69
70 trie->num_prefixes = sorted_prefix_matches.size();
71
72 uint32_t prefix_entries_array_offset = arena_->AllocateUint32Array(sorted_prefix_matches.size());
73 trie->prefix_entries = prefix_entries_array_offset;
74
75 for (unsigned int i = 0; i < sorted_prefix_matches.size(); ++i) {
76 uint32_t property_entry_offset = WritePropertyEntry(sorted_prefix_matches[i]);
77 arena_->uint32_array(prefix_entries_array_offset)[i] = property_entry_offset;
78 }
79
80 // Write exact matches
81 auto sorted_exact_matches = builder_node.exact_matches();
82 // Exact matches are sorted alphabetically
83 std::sort(sorted_exact_matches.begin(), sorted_exact_matches.end(),
84 [](const auto& lhs, const auto& rhs) { return lhs.name < rhs.name; });
85
86 trie->num_exact_matches = sorted_exact_matches.size();
87
88 uint32_t exact_match_entries_array_offset =
89 arena_->AllocateUint32Array(sorted_exact_matches.size());
90 trie->exact_match_entries = exact_match_entries_array_offset;
91
92 for (unsigned int i = 0; i < sorted_exact_matches.size(); ++i) {
93 uint32_t property_entry_offset = WritePropertyEntry(sorted_exact_matches[i]);
94 arena_->uint32_array(exact_match_entries_array_offset)[i] = property_entry_offset;
95 }
96
97 // Write children
98 auto sorted_children = builder_node.children();
99 std::sort(sorted_children.begin(), sorted_children.end(),
100 [](const auto& lhs, const auto& rhs) { return lhs.name() < rhs.name(); });
101
102 trie->num_child_nodes = sorted_children.size();
103 uint32_t children_offset_array_offset = arena_->AllocateUint32Array(sorted_children.size());
104 trie->child_nodes = children_offset_array_offset;
105
106 for (unsigned int i = 0; i < sorted_children.size(); ++i) {
107 arena_->uint32_array(children_offset_array_offset)[i] = WriteTrieNode(sorted_children[i]);
108 }
109 return trie_offset;
110}
111
112TrieSerializer::TrieSerializer() {}
113
114std::string TrieSerializer::SerializeTrie(const TrieBuilder& trie_builder) {
115 arena_.reset(new TrieNodeArena());
116
117 auto header = arena_->AllocateObject<PropertyInfoAreaHeader>(nullptr);
118 header->current_version = 1;
119 header->minimum_supported_version = 1;
120
121 // Store where we're about to write the contexts.
122 header->contexts_offset = arena_->size();
123 SerializeStrings(trie_builder.contexts());
124
125 // Store where we're about to write the schemas.
126 header->schemas_offset = arena_->size();
127 SerializeStrings(trie_builder.schemas());
128
129 // We need to store size() up to this point now for Find*Offset() to work.
130 header->size = arena_->size();
131
132 uint32_t root_trie_offset = WriteTrieNode(trie_builder.builder_root());
133 header->root_offset = root_trie_offset;
134
135 // Record the real size now that we've written everything
136 header->size = arena_->size();
137
138 return arena_->truncated_data();
139}
140
141} // namespace properties
142} // namespace android
diff --git a/property_service/libpropertyinfoserializer/trie_serializer.h b/property_service/libpropertyinfoserializer/trie_serializer.h
new file mode 100644
index 000000000..e4d3343a0
--- /dev/null
+++ b/property_service/libpropertyinfoserializer/trie_serializer.h
@@ -0,0 +1,55 @@
1//
2// Copyright (C) 2017 The Android Open Source Project
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15//
16
17#ifndef PROPERTY_INFO_SERIALIZER_TRIE_SERIALIZER_H
18#define PROPERTY_INFO_SERIALIZER_TRIE_SERIALIZER_H
19
20#include <string>
21#include <vector>
22
23#include "property_info_parser/property_info_parser.h"
24
25#include "trie_builder.h"
26#include "trie_node_arena.h"
27
28namespace android {
29namespace properties {
30
31class TrieSerializer {
32 public:
33 TrieSerializer();
34
35 std::string SerializeTrie(const TrieBuilder& trie_builder);
36
37 private:
38 void SerializeStrings(const std::set<std::string>& strings);
39 uint32_t WritePropertyEntry(const PropertyEntryBuilder& property_entry);
40
41 // Writes a new TrieNode to arena, and recursively writes its children.
42 // Returns the offset within arena.
43 uint32_t WriteTrieNode(const TrieBuilderNode& builder_node);
44
45 const PropertyInfoArea* serialized_info() const {
46 return reinterpret_cast<const PropertyInfoArea*>(arena_->data().data());
47 }
48
49 std::unique_ptr<TrieNodeArena> arena_;
50};
51
52} // namespace properties
53} // namespace android
54
55#endif