Tom Cherry | fd44b9f | 2017-11-08 14:01:00 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2008 The Android Open Source Project |
| 3 | * All rights reserved. |
| 4 | * |
| 5 | * Redistribution and use in source and binary forms, with or without |
| 6 | * modification, are permitted provided that the following conditions |
| 7 | * are met: |
| 8 | * * Redistributions of source code must retain the above copyright |
| 9 | * notice, this list of conditions and the following disclaimer. |
| 10 | * * Redistributions in binary form must reproduce the above copyright |
| 11 | * notice, this list of conditions and the following disclaimer in |
| 12 | * the documentation and/or other materials provided with the |
| 13 | * distribution. |
| 14 | * |
| 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS |
| 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE |
| 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, |
| 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, |
| 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS |
| 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED |
| 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
| 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
| 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
| 26 | * SUCH DAMAGE. |
| 27 | */ |
| 28 | |
| 29 | #include <stdatomic.h> |
| 30 | #include <stdint.h> |
| 31 | #include <string.h> |
Tom Cherry | f76bbf5 | 2017-11-08 14:01:00 -0800 | [diff] [blame] | 32 | #include <sys/mman.h> |
Tom Cherry | fd44b9f | 2017-11-08 14:01:00 -0800 | [diff] [blame] | 33 | |
| 34 | #include "private/bionic_macros.h" |
| 35 | |
| 36 | #include "prop_info.h" |
| 37 | |
| 38 | #ifndef SYSTEM_PROPERTIES_PROP_AREA_H |
| 39 | #define SYSTEM_PROPERTIES_PROP_AREA_H |
| 40 | |
| 41 | // Properties are stored in a hybrid trie/binary tree structure. |
| 42 | // Each property's name is delimited at '.' characters, and the tokens are put |
| 43 | // into a trie structure. Siblings at each level of the trie are stored in a |
| 44 | // binary tree. For instance, "ro.secure"="1" could be stored as follows: |
| 45 | // |
| 46 | // +-----+ children +----+ children +--------+ |
| 47 | // | |-------------->| ro |-------------->| secure | |
| 48 | // +-----+ +----+ +--------+ |
| 49 | // / \ / | |
| 50 | // left / \ right left / | prop +===========+ |
| 51 | // v v v +-------->| ro.secure | |
| 52 | // +-----+ +-----+ +-----+ +-----------+ |
| 53 | // | net | | sys | | com | | 1 | |
| 54 | // +-----+ +-----+ +-----+ +===========+ |
| 55 | |
| 56 | // Represents a node in the trie. |
| 57 | struct prop_bt { |
| 58 | uint32_t namelen; |
| 59 | |
| 60 | // The property trie is updated only by the init process (single threaded) which provides |
| 61 | // property service. And it can be read by multiple threads at the same time. |
| 62 | // As the property trie is not protected by locks, we use atomic_uint_least32_t types for the |
| 63 | // left, right, children "pointers" in the trie node. To make sure readers who see the |
| 64 | // change of "pointers" can also notice the change of prop_bt structure contents pointed by |
| 65 | // the "pointers", we always use release-consume ordering pair when accessing these "pointers". |
| 66 | |
| 67 | // prop "points" to prop_info structure if there is a propery associated with the trie node. |
| 68 | // Its situation is similar to the left, right, children "pointers". So we use |
| 69 | // atomic_uint_least32_t and release-consume ordering to protect it as well. |
| 70 | |
| 71 | // We should also avoid rereading these fields redundantly, since not |
| 72 | // all processor implementations ensure that multiple loads from the |
| 73 | // same field are carried out in the right order. |
| 74 | atomic_uint_least32_t prop; |
| 75 | |
| 76 | atomic_uint_least32_t left; |
| 77 | atomic_uint_least32_t right; |
| 78 | |
| 79 | atomic_uint_least32_t children; |
| 80 | |
| 81 | char name[0]; |
| 82 | |
| 83 | prop_bt(const char* name, const uint32_t name_length) { |
| 84 | this->namelen = name_length; |
| 85 | memcpy(this->name, name, name_length); |
| 86 | this->name[name_length] = '\0'; |
| 87 | } |
| 88 | |
| 89 | private: |
| 90 | DISALLOW_COPY_AND_ASSIGN(prop_bt); |
| 91 | }; |
| 92 | |
| 93 | class prop_area { |
| 94 | public: |
| 95 | static prop_area* map_prop_area_rw(const char* filename, const char* context, |
| 96 | bool* fsetxattr_failed); |
| 97 | static prop_area* map_prop_area(const char* filename); |
Tom Cherry | f76bbf5 | 2017-11-08 14:01:00 -0800 | [diff] [blame] | 98 | static void unmap_prop_area(prop_area** pa) { |
| 99 | if (*pa) { |
| 100 | munmap(*pa, pa_size_); |
| 101 | *pa = nullptr; |
| 102 | } |
| 103 | } |
Tom Cherry | fd44b9f | 2017-11-08 14:01:00 -0800 | [diff] [blame] | 104 | |
| 105 | prop_area(const uint32_t magic, const uint32_t version) : magic_(magic), version_(version) { |
| 106 | atomic_init(&serial_, 0); |
| 107 | memset(reserved_, 0, sizeof(reserved_)); |
| 108 | // Allocate enough space for the root node. |
| 109 | bytes_used_ = sizeof(prop_bt); |
| 110 | } |
| 111 | |
| 112 | const prop_info* find(const char* name); |
| 113 | bool add(const char* name, unsigned int namelen, const char* value, unsigned int valuelen); |
| 114 | |
| 115 | bool foreach (void (*propfn)(const prop_info* pi, void* cookie), void* cookie); |
| 116 | |
| 117 | atomic_uint_least32_t* serial() { |
| 118 | return &serial_; |
| 119 | } |
| 120 | uint32_t magic() const { |
| 121 | return magic_; |
| 122 | } |
| 123 | uint32_t version() const { |
| 124 | return version_; |
| 125 | } |
| 126 | |
| 127 | private: |
| 128 | static prop_area* map_fd_ro(const int fd); |
| 129 | |
| 130 | void* allocate_obj(const size_t size, uint_least32_t* const off); |
| 131 | prop_bt* new_prop_bt(const char* name, uint32_t namelen, uint_least32_t* const off); |
| 132 | prop_info* new_prop_info(const char* name, uint32_t namelen, const char* value, uint32_t valuelen, |
| 133 | uint_least32_t* const off); |
| 134 | void* to_prop_obj(uint_least32_t off); |
| 135 | prop_bt* to_prop_bt(atomic_uint_least32_t* off_p); |
| 136 | prop_info* to_prop_info(atomic_uint_least32_t* off_p); |
| 137 | |
| 138 | prop_bt* root_node(); |
| 139 | |
| 140 | prop_bt* find_prop_bt(prop_bt* const bt, const char* name, uint32_t namelen, bool alloc_if_needed); |
| 141 | |
| 142 | const prop_info* find_property(prop_bt* const trie, const char* name, uint32_t namelen, |
| 143 | const char* value, uint32_t valuelen, bool alloc_if_needed); |
| 144 | |
| 145 | bool foreach_property(prop_bt* const trie, void (*propfn)(const prop_info* pi, void* cookie), |
| 146 | void* cookie); |
| 147 | |
Tom Cherry | f76bbf5 | 2017-11-08 14:01:00 -0800 | [diff] [blame] | 148 | // The original design doesn't include pa_size or pa_data_size in the prop_area struct itself. |
| 149 | // Since we'll need to be backwards compatible with that design, we don't gain much by adding it |
| 150 | // now, especially since we don't have any plans to make different property areas different sizes, |
| 151 | // and thus we share these two variables among all instances. |
| 152 | static size_t pa_size_; |
| 153 | static size_t pa_data_size_; |
| 154 | |
Tom Cherry | fd44b9f | 2017-11-08 14:01:00 -0800 | [diff] [blame] | 155 | uint32_t bytes_used_; |
| 156 | atomic_uint_least32_t serial_; |
| 157 | uint32_t magic_; |
| 158 | uint32_t version_; |
| 159 | uint32_t reserved_[28]; |
| 160 | char data_[0]; |
| 161 | |
| 162 | DISALLOW_COPY_AND_ASSIGN(prop_area); |
| 163 | }; |
| 164 | |
| 165 | #endif |