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