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 #include <stdlib.h>
22 
23 static constexpr char PROP_TREE_FILE[] = "/dev/__properties__/property_info";
24 
25 namespace android {
26 namespace properties {
27 
28 // The below structs intentionally do not end with char name[0] or other tricks to allocate
29 // with a dynamic size, such that they can be added onto in the future without breaking
30 // backwards compatibility.
31 struct PropertyEntry {
32   uint32_t name_offset;
33   uint32_t namelen;
34 
35   // This is the context match for this node_; ~0u if it doesn't correspond to any.
36   uint32_t context_index;
37   // This is the type for this node_; ~0u if it doesn't correspond to any.
38   uint32_t type_index;
39 };
40 
41 struct TrieNodeInternal {
42   // This points to a property entry struct, which includes the name for this node
43   uint32_t property_entry;
44 
45   // Children are a sorted list of child nodes_; binary search them.
46   uint32_t num_child_nodes;
47   uint32_t child_nodes;
48 
49   // Prefixes are terminating prefix matches at this node, sorted longest to smallest
50   // Take the first match sequentially found with StartsWith().
51   uint32_t num_prefixes;
52   uint32_t prefix_entries;
53 
54   // Exact matches are a sorted list of exact matches at this node_; binary search them.
55   uint32_t num_exact_matches;
56   uint32_t exact_match_entries;
57 };
58 
59 struct PropertyInfoAreaHeader {
60   // The current version of this data as created by property service.
61   uint32_t current_version;
62   // The lowest version of libc that can properly parse this data.
63   uint32_t minimum_supported_version;
64   uint32_t size;
65   uint32_t contexts_offset;
66   uint32_t types_offset;
67   uint32_t root_offset;
68 };
69 
70 class SerializedData {
71  public:
size()72   uint32_t size() const {
73     return reinterpret_cast<const PropertyInfoAreaHeader*>(data_base_)->size;
74   }
75 
c_string(uint32_t offset)76   const char* c_string(uint32_t offset) const {
77     if (offset != 0 && offset > size()) return nullptr;
78     return static_cast<const char*>(data_base_ + offset);
79   }
80 
uint32_array(uint32_t offset)81   const uint32_t* uint32_array(uint32_t offset) const {
82     if (offset != 0 && offset > size()) return nullptr;
83     return reinterpret_cast<const uint32_t*>(data_base_ + offset);
84   }
85 
uint32(uint32_t offset)86   uint32_t uint32(uint32_t offset) const {
87     if (offset != 0 && offset > size()) return ~0u;
88     return *reinterpret_cast<const uint32_t*>(data_base_ + offset);
89   }
90 
data_base()91   const char* data_base() const { return data_base_; }
92 
93  private:
94   const char data_base_[0];
95 };
96 
97 class TrieNode {
98  public:
TrieNode()99   TrieNode() : serialized_data_(nullptr), trie_node_base_(nullptr) {}
TrieNode(const SerializedData * data_base,const TrieNodeInternal * trie_node_base)100   TrieNode(const SerializedData* data_base, const TrieNodeInternal* trie_node_base)
101       : serialized_data_(data_base), trie_node_base_(trie_node_base) {}
102 
name()103   const char* name() const {
104     return serialized_data_->c_string(node_property_entry()->name_offset);
105   }
106 
context_index()107   uint32_t context_index() const { return node_property_entry()->context_index; }
type_index()108   uint32_t type_index() const { return node_property_entry()->type_index; }
109 
num_child_nodes()110   uint32_t num_child_nodes() const { return trie_node_base_->num_child_nodes; }
child_node(int n)111   TrieNode child_node(int n) const {
112     uint32_t child_node_offset = serialized_data_->uint32_array(trie_node_base_->child_nodes)[n];
113     const TrieNodeInternal* trie_node_base =
114         reinterpret_cast<const TrieNodeInternal*>(serialized_data_->data_base() + child_node_offset);
115     return TrieNode(serialized_data_, trie_node_base);
116   }
117 
118   bool FindChildForString(const char* input, uint32_t namelen, TrieNode* child) const;
119 
num_prefixes()120   uint32_t num_prefixes() const { return trie_node_base_->num_prefixes; }
prefix(int n)121   const PropertyEntry* prefix(int n) const {
122     uint32_t prefix_entry_offset =
123         serialized_data_->uint32_array(trie_node_base_->prefix_entries)[n];
124     return reinterpret_cast<const PropertyEntry*>(serialized_data_->data_base() +
125                                                   prefix_entry_offset);
126   }
127 
num_exact_matches()128   uint32_t num_exact_matches() const { return trie_node_base_->num_exact_matches; }
exact_match(int n)129   const PropertyEntry* exact_match(int n) const {
130     uint32_t exact_match_entry_offset =
131         serialized_data_->uint32_array(trie_node_base_->exact_match_entries)[n];
132     return reinterpret_cast<const PropertyEntry*>(serialized_data_->data_base() +
133                                                   exact_match_entry_offset);
134   }
135 
136  private:
node_property_entry()137   const PropertyEntry* node_property_entry() const {
138     return reinterpret_cast<const PropertyEntry*>(serialized_data_->data_base() +
139                                                   trie_node_base_->property_entry);
140   }
141 
142   const SerializedData* serialized_data_;
143   const TrieNodeInternal* trie_node_base_;
144 };
145 
146 class PropertyInfoArea : private SerializedData {
147  public:
148   void GetPropertyInfoIndexes(const char* name, uint32_t* context_index, uint32_t* type_index) const;
149   void GetPropertyInfo(const char* property, const char** context, const char** type) const;
150 
151   int FindContextIndex(const char* context) const;
152   int FindTypeIndex(const char* type) const;
153 
context(uint32_t index)154   const char* context(uint32_t index) const {
155     uint32_t context_array_size_offset = contexts_offset();
156     const uint32_t* context_array = uint32_array(context_array_size_offset + sizeof(uint32_t));
157     return data_base() + context_array[index];
158   }
159 
type(uint32_t index)160   const char* type(uint32_t index) const {
161     uint32_t type_array_size_offset = types_offset();
162     const uint32_t* type_array = uint32_array(type_array_size_offset + sizeof(uint32_t));
163     return data_base() + type_array[index];
164   }
165 
current_version()166   uint32_t current_version() const { return header()->current_version; }
minimum_supported_version()167   uint32_t minimum_supported_version() const { return header()->minimum_supported_version; }
168 
size()169   uint32_t size() const { return SerializedData::size(); }
170 
num_contexts()171   uint32_t num_contexts() const { return uint32_array(contexts_offset())[0]; }
num_types()172   uint32_t num_types() const { return uint32_array(types_offset())[0]; }
173 
root_node()174   TrieNode root_node() const { return trie(header()->root_offset); }
175 
176  private:
177   void CheckPrefixMatch(const char* remaining_name, const TrieNode& trie_node,
178                         uint32_t* context_index, uint32_t* type_index) const;
179 
header()180   const PropertyInfoAreaHeader* header() const {
181     return reinterpret_cast<const PropertyInfoAreaHeader*>(data_base());
182   }
contexts_offset()183   uint32_t contexts_offset() const { return header()->contexts_offset; }
contexts_array_offset()184   uint32_t contexts_array_offset() const { return contexts_offset() + sizeof(uint32_t); }
types_offset()185   uint32_t types_offset() const { return header()->types_offset; }
types_array_offset()186   uint32_t types_array_offset() const { return types_offset() + sizeof(uint32_t); }
187 
trie(uint32_t offset)188   TrieNode trie(uint32_t offset) const {
189     if (offset != 0 && offset > size()) return TrieNode();
190     const TrieNodeInternal* trie_node_base =
191         reinterpret_cast<const TrieNodeInternal*>(data_base() + offset);
192     return TrieNode(this, trie_node_base);
193   }
194 };
195 
196 // This is essentially a smart pointer for read only mmap region for property contexts.
197 class PropertyInfoAreaFile {
198  public:
PropertyInfoAreaFile()199   PropertyInfoAreaFile() : mmap_base_(nullptr), mmap_size_(0) {}
~PropertyInfoAreaFile()200   ~PropertyInfoAreaFile() { Reset(); }
201 
202   PropertyInfoAreaFile(const PropertyInfoAreaFile&) = delete;
203   void operator=(const PropertyInfoAreaFile&) = delete;
204   PropertyInfoAreaFile(PropertyInfoAreaFile&&) = default;
205   PropertyInfoAreaFile& operator=(PropertyInfoAreaFile&&) = default;
206 
207   bool LoadDefaultPath();
208   bool LoadPath(const char* filename);
209 
210   const PropertyInfoArea* operator->() const {
211     return reinterpret_cast<const PropertyInfoArea*>(mmap_base_);
212   }
213 
214   explicit operator bool() const { return mmap_base_ != nullptr; }
215 
216   void Reset();
217 
218  private:
219   void* mmap_base_;
220   size_t mmap_size_;
221 };
222 
223 }  // namespace properties
224 }  // namespace android
225 
226 #endif
227